视频课:https://edu.csdn.net/course/play/7621

本章简介

第3章讲解了视图状态、Flex页面间的跳转、Flex应用的模态窗体、数据绑定、使用拖放,图表等知识。本章将学习Flex与外部的数据通信。在实际开发过程中,Flex应用的数据往往来自于业务逻辑数据提供的服务器端。虽然Flex是用于开发富客户端界面的强大平台,可以编写业务逻辑,但从架构的角度看,仍然需要将核心的业务逻辑放在Flex程序之外。Flex与外部程序的数据通信主要包括HTTPService. WebService和Remoting 3种方式。

核心技能部分

 

 

从分层角度来看,企业应用系统主要分为三个层次,如表4-1-1所示。

表5-1-1企业应用主要分层

企业应用层次

 

职责简介

 

展现层

主要负责信息展示和人机交互的相关逻辑

领域层

主要完成企业应用业务逻辑,是系统的核心部分

数据源层

负责数据的提取和持久化

展现层主要负责信息展示以及用户与软件之间的交互逻辑,“展现层”接受用户输入并将用户的意图转换为对“领域层’或“数据源层’逻辑的调用。

领域层也被称为“业务逻辑层”,主要解决应用所针对业务领域的问题。该层负责校验来自“展现层”的输人数据,根据“展现层’用户指令进行业务逻辑处理,调用“数据源层’的逻辑实现数据的访问和持久化。

数据源层主要负责数据访问和持久化,数据可能来自于数据库或者消息系统。对干绝大多数企业应用来说,数据源层主要负责同数据库系统的交互。

Flex+Java企业应用中,“展现层’逻辑完全运行在客户端的Flash虚拟机中,而“领域层”和“数据源层”逻辑则运行在服务器端的Java虚拟机中,如图5.1.1所示。

 

5.1.1 Flex+java企业应用层次逻辑分布图

   

 从图5.1.1中可以看出,客户端系统与服务端系统完全用不同的语言实现,因此系统是异构的。同时,客户端代码运行在客户端的ActionScript虚拟机中。而服务器端代码则运行在服务器上的Java虚拟机中,因此系统又是分布式的。这与我们开发传统Web应用完全不同,

传统Web应用中所有Java代码,包括业务逻辑代码和生成人机界面的代码都在服务器Java虚拟机中执行,如图5.1.2所示。

 

5.1.2 传统web应用层次逻辑分布图

    基于传统Web技术进行开发,很多开发者已经习惯了“接受客户端的请求,然后执行业务逻轼,最后输出人机界面”这种工作模式。基于Jsp技术的MVC框架,比如Struts,Jsf等,都是基于这种工作模式开发的。

    因此、Flex+Java所开发的BS应用与传统Web所开发的B/S系统最大的区就是:使用Flex+Java开发的B/S应用系统中,B系统(客户端系统)S系统(服务器端系统)完全分离、各自独立地运行在不同的CPU和虚拟机中。B系统主要负责“展现层”逻辑,而S系统主要负责“领域层”和“数据源层”逻辑。因此,Flex+J ava所开发的企业应用系统是异构的分布式系统,这种异构分布式系统给我们带来了以下需要思考的问题:

Ø 异构的客户端系统和服务器端系统如何通信?

Ø 如何保持分布式的客户端系统和服务器端系统之间的状态一致性?

    我们在进行架构设计时,必须要清楚并解决这些问题,才能顺利进行企业应用开发,下面两个小节主要针对以上两个问题进行阐述,并给出解决方案。

1.1 确定Flex客户端系统和Java服务器端通信框架

    开发异构系统时,如何进行通信和传递数据是我们比较关注的问题。使用Flex+Java开发基于B/S结构企业应用,客户端和服务器端的通信协议是我们所熟知的HTTP协议。在Flex中,基于HTTP协议访问服务器的通信组件有三个:

Ø    HttpService(mx.rpc.http.mxml.HTTPService)

Ø    WebService(mx.rpc.soap.mxml.WebService)

Ø    RemoteObject(mx.rpc.remoting.mxml.RemoteObject)

HttpService组件可以调用很多不同技术的服务端页面,比如JSP,ASP ,PHP,Servlet等在大多数情况下,使用HttpService访问服务器端页面来完成Flex客户端与服务器端的数据交互,服务器端返回的结果一般都是XML格式的数据。下面是Adobe官方关于HTTPService组件的例子应用:

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"

   creationComplete="feedRequest.send()" layout="absolute">

   <mx:HTTPService id="feedRequest"

      url="http://weblogs.macromedia.com/mchotin/index.xml"

      useProxy="false" />

   <mx:Panel x="10" y="10" width="475" height="400"

        title="{feedRequest.lastResult.rss.channel.title}">

       <mx:DataGrid id="dgPosts" x="20" y="20" width="400"

           dataProvider="{feedRequest.lastResult.rss.channel.item}">

           <mx:columns>

              <mx:DataGridColumn headerText="Posts" dataField="title"/>

              <mx:DataGridColumn headerText="Date"

                   dataField="pubDate" width="150" />

           </mx:columns>

       </mx:DataGrid>

       <mx:LinkButton x="20" y="225" label="Read Full Post"

                   click="navigateToURL(new URLRequest(dgPosts.selectedItem.link));"/>

       <mx:TextArea x="20" y="175" width="400"/>

   </mx:Panel>

</mx:Application>

这个例子的运行需要能够访问互联网,在本例中通过调用URLhttp://weblogs.macromedia.com/mchotin/index.xmlHTTPService ,返回了一个XML文件,并将这个XML作为Datagrid控件的dataProvider,从而通过DatagridXML文件中的数据展示出来。XML中的数据主要是网站最近的发帖记录。这个例子说明,HTTPService的工作方式主要通过请求URL获取XML格式数据。

上例运行后 效果如图5.1.3所示。

 

5.1.3 HttpService 示例

    HTTPService类似,Flex应用可以调用URL所表示WSDL 1.1服务,返回SOAP1.1格式的调用结果。SOAP也是基于XML格式规范,因此。使用HTTPServiceWebService组件同服务器之间的交互都是通过XML进行的。下面是Adobe官方关于WebService组件的例子应用。  

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"

layout="absolute"

creationComplete="wsBlogAggr.getMostPopularPosts.send()">

<mx:WebService id="wsBlogAggr"

     wsdl="http://weblogs.macromedia.com/mxna/webservices/

mxna2.cfc?wsdl"

     useProxy="false">

      <mx:operation name="getMostPopularPosts">

         <mx:request>

            <daysBack>30</daysBack>

             <limit>{cbxNumPosts.value}</limit>

         </mx:request>

     </mx:operation>

</mx:WebService>

<mx:Panel x="10" y="10" width="475" height="400" layout="absolute"

    title="Most Popular Posts">

    <mx:ComboBox x="30" y="25" id="cbxNumPosts"

       change="wsBlogAggr.getMostPopularPosts.send()">

       <mx:Object label="Top 5" data="5" />

       <mx:Object label="Top 10" data="10" />

       <mx:Object label="Top 15" data="15" />

    </mx:ComboBox>

    <mx:DataGrid x="30" y="75" id="dgTopPosts" width="400"

      dataProvider="{wsBlogAggr.getMostPopularPosts.lastResult}">

<mx:columns>

<mx:DataGridColumn headerText="Top Posts"

dataField="postTitle"/>

<mx:DataGridColumn headerText="Clicks" dataField="clicks"

width="75"/>

</mx:columns>

</mx:DataGrid>

<mx:LinkButton x="30" y="250"

label="Select an item and click here for full post"/>

</mx:Panel>

</mx:Application>

 

  在这个例子中,通过WebService组件调用了服务器所提供的WebService服务,返回SOAP

格式的XML数据,根据请求参数,XML数据表示网站中最近30天的点击率排名前5,10或者15的博客。

  通过这两个例子我们可以看到,使用HTTPServiceWebService无需第三方框架,在服务器端直接编写相应的服务即可,所以比较容易理解和使用。但是,无论使用HTTPService还是WebService访问服务器,Flex客户端和服务器之间传递的都是XML数据,客户端和服务器端处理的也是XML数据。对于企业应用来说,客户端和服务器端交互的数据量往往很大,因此使用XML作为数据交换格式会降低传输效率和转换效率。同时,处理XML数据的代码也远比处理对象的代码繁琐,并且难以阅读和调试。因此,在企业应用开发中,客户端系统和服务器端系统之间采用HTTPServiceWebService进行通信的部分较少,即使使用这两个组件。也应当用来传递少量、数据格式不易发生变化的数据。

    在企业应用开发中,Flex客户端与后台服务器之间的大量通信都是采用RemoteObject完成的。RemoteObject组件在“第三方软件”的配合下,能够调用后台服务器对象上的方法,比如Java对象或者.net对象上的方法,从而实现客户端与服务器端的通信。在客户端使用RemoteObject可以直接将ActionScript对象作为调用的参数和返回结果。这一点听起来似乎有些神奇,但其实也很容易理解:Adobe公司定义了一种二进制数据格式AMF(Action Message Format),用于客户端与服务器端的数据交互。    其实,使用AMF格式交换数据与使用XML进行数据交换的主要区别在于: AMF二进制数据的转换和传输效率更高,同时需要“第三方软件”用于解释AMF格式数据。Flex客户端RemoteObject组件与服务器端通过HTTP协议传递AMF格式的二进制数据进行通信的大致过程如下:

    1)客户端RemoteObject将调用参数中的ActionScript对象序列化为AMF数据格式,然后发出调用请求。

    2)服务器的“第三方软件“获取HTTP请求流。

    3)服务器的“第三方软件”对HTTP请求流进行解析,并且建立响应消息。对HTTP请求流进行解析,解析过程包括解释AMF格式数据,将ActionScript对象的AMF数据按照事先确定的协议“反序列化”为服务器端对象,比如Java对象,然后用这些参数调用客户端指定的服务器对象上的方法。

    4)服务器的“第三方软件,将调用的结果“序列化”为AMF格式的数据流。

    5)服务器发送HTTP响应给Fee客户端。

    6) Flex客户端解释AMF格式数据流,将调用结果序列化为ActionScript对象。

下面我们给出一段Flex官方文档代码来展示Rernoteobject对象的使用:

<?xml version="1.0"?>

 

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

    <mx:Script>

        <![CDATA[

            import mx.controls.Alert;

            import mx.rpc.remoting.RemoteObject;

            import mx.rpc.events.ResultEvent;

            import mx.rpc.events.FaultEvent;

            [Bindable]

            public var empList:Object;          

            public var employeeRO:RemoteObject;

            public function useRemoteObject(intArg:int, strArg:String):void {

                employeeRO = new RemoteObject();

                employeeRO.destination = "SalaryManager";

                employeeRO.getList.addEventListener("result",

                                                           getListResultHandler);

                employeeRO.addEventListener("fault", faultHandler);

                employeeRO.getList(deptComboBox.selectedItem.data);

            }

            public function getListResultHandler(event:ResultEvent):void {

                 // 远程调用成功所要完成的处理。

                empList=event.result;

            }

 

            public function faultHandler (event:FaultEvent):void {

             // 调用失败所要完成的处理。

                Alert.show(event.fault.faultString, 'Error');

            }

        ]]>

    </mx:Script>

    <mx:ComboBox id="deptComboBox"/>

</mx:Application>

 

在上面的代码中首先看一下函数useRemoteObject这个函数中首先使用语句:

  employeeRO = new RemoteObject();

创建了一个RemoteObject对象employeeRo。然后通过语句:

employeeRO.destination = "SalaryManager";

RemoteObject对象的destination属性赋值为一个字符串" SalaryManager "destination属性表示远程对象调用的“目的地’,请求发送到服务器端后,服务器端的“第三方软件’接收到请求后会检查配置文件,找到destination值所映射的“服务器端组件”,从而可以调用该组件上的方法。接下来使用语句:

employeeRO.getList.addEventListener("result", getListResultHandler);    

设置远程服务调用成功时的处理方法,使用语句:

employeeRO.addEventListener("fault", faultHandler);

设置远程服务调用失败时的处理方法。最后,使用语句:

employeeRO.getList(deptComboBox.selectedItem.data);

以deptComboBox.selectedItem.data为参数,调用destination属性所映射的“服务器端组件”的getList方法,这里,“服务端组件”必须有一个名为getList的公开方法,调用“服务器端组件”的getList方法是异步调用,因此它不会阻塞线程来等待调用结果的返回,调用结果的返回时会在getListResultHandler方法中进行处理。在getListlRsultHandler方法中,我们到语句:

empList=event.result;

    该语句表示远程调用所返回的结果event.result可以直接赋值给ActionScript对象。当然,

后端返回的对象类型与Flex客户端的ActionScript对象类型要满足“第三方软件’所规定的对象类型之间的“映射规则,这样,Flex就可以把后台返回的AMF数据流自动地序列化为ActionScript对象。

    从上面的代码分析中我们可以看出:同传递XML方式相比,RemoteObject调用方式直接将ActionScript对象作为调用的参数和返回结果,这对于开发者编程特别方便。同时,通过RemoteObject调用远程方法需要多写几行代码,但通过精巧的封装可以很好地解决这个问题。

在上面的论述中多次提到了“第三方软件”,要使用RemoteObject组件进行远程方法调用,那么必须在服务器上部署和配置相应的“第三方软件”。“第三方软件”有两个最基本的作用:

Ø 服务器端对象序列化为AMF格式数据和将AMF格式数据反序列化为服务器端对象。

Ø 将客户端的请求映射为服务器端相应对象上的方法调用。

由于AMF规范已经公开,因此,有很多“第三方软件”支持不同的后台服务器端语言,在.net平台下比较著名的“第三方软件”为Midnight Coders WebORB

我们所关心的Java平台“下的“第三方软件”有Adobe官方商业收费软件LifeCycle  Data  Service(LCDS)Adobe官方开源软件BlazeDS

BlazeDSLCDS的开源版,只不过BlazeDS不具备LCDS的一些高级功能,比如:

Ø 高级客户端-服务器数据同步功能。

Ø 冲突检测/解决。

Ø Adobe AIR应用的离线数据管理服务。

Ø RIA生成PDF等。

使用BlazeDSLCDS进行企业应用开发的配置完全一样,因此,在不需要LCDS高级功能的情况下,完全可以使用BlazeDS替换LCDS作为一种廉价方案,必须使用LCDS高级功能时用户可以追加投资购买LCDS,因此基于BlazeDS企业应用可以很容易升级为基于LCDS的企业应用,这也是我们选择BlazeDS作为配合RemoteObject远程调用的“第三方软件”的主要原因。

因此,使用Flex+Java开发企业应用,我们主要使用RemoteObject+BlazeDS实现Flex端与Java端的通信。

总之,使用RemoteObject+BlazeDS作为Flex端同Java服务器端的通信框架有如下优点:

Ø 以二进制的AMF协议传递数据,转换和传输数据的性能高于XML格式。

Ø 使用RemoteObject+BlazeDS能够实现Flex对象与Java对象之间的自动转换,更加有利于开发者编程。

Ø 使用开源框架BlazeDS所开发的企业应用可以更容易地升级为采用高端商业软件LCDS作为数据通信框架的企业应用。

当然,还有一些其他开源框架,比如Hessian。和Granite也能够完成与BlazeDS类似的功能,开发者可以根据实际情况加以选择,但是由于它们的原理相同,所以可以使用相同架构方法和设计模式。

1.2 构建一个简单的BlazeDS应用

    本节的任务是创建一个RemoteObject应用程序,这个应用程序包括两部分:前端Flex应用和后端Java应用。两者通过BlazeDS通信, 开发步骤如下

1.准备软件环境

在Flex应用中使用Remoting技术时需要以下软件: 

Ø  MyEclipse 7.5及以上版本。 

Ø Adobe Flash Builder 4 Plug-in。 

Ø Tomcat 5.5及以上版本。 

Ø JDK l.6及以上版本。 

Ø BlazeDS 3.2及以上版本。 

2.安装配置软件

安装配置软件需要按照以下顺序: 

Ø 安装MyEclipse 7.5。 

Ø 安装Adobe Flash Builder 4 Plug-in.

MyEclipse7.5安装完成后将创建一个Common文件夹和启动程序所在文件夹(默认命名为“MyEclipse 7.5”)。启动程序所在文件夹中包含一个dropins文件夹,该文件夹是MyEclipse7.5中安装Adobe Flash Builder 4 Plug-in时所需的文件夹。选择“再插入一个Eclipse”项,单击“选择”按钮,选择MyEclipse启动程序所在的文件夹进行安装,如图5.1.4所示。 

 

5.1.4 安装Adobe Flash Bulider 4 Plug-in

Ø 安装BlazeDS 3.2。 

通过http://opensource.adobe.com/wiki/display/blazeds/Downloads地址下载Binary Distribution版本的BlazeDS软件。该版本为最简版本,解压后只包含一个blazeds.war文件。在创建Flex项目时,为了在项目中通过BlazeDS使用Remoting技术,需要定位blazeds.war文件。 

Ø 在MyEclipse 7.5中配置Tomcat和JDK。 

3.开发基于Remoting技术的Flex应用程序

开发基于Remoting技术的Flex应用程序步骤如下: 

Ø 启动MyEclipse 7.5,单击右上角的【Flash】按钮,切换至Flex应用开发视图。选择“file’

à“new”à“Flex项目”。弹出“新建Flex项目”对话框,按提示进行操作,如图5.1.5所示。

 

5.1.5 新建Flex项目

Ø 在图5.1.5中单击“Next”按报,弹出“配置J2EE服务器”对话框,按提示进行操作, 如图5.1.6所示。 

 

5.1.6 配置J2EE服务器

Ø 在图5.1.6中单击“Next”按钮,弹出“新建Flex项目”对话框,为Flex项目设置捌径,按提示进行操作,如图5.1.7所示。 

 

5.1.7 Flex项目设置构建路径

Ø 在图5.1.7中,单击【Finish】按钮,完成创建Flex项目的操作,生成的项目文件结构如图5.1.8所示。

 

5.1.8 Flex项目文件结构图

Ø 编辑生成的remotingApp.mxml文件,向其中添加以下代码: 

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

   xmlns:s="library://ns.adobe.com/flex/spark"

   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">

<fx:Declarations>

<!-- 将非可视元素(例如服务、值对象)放在此处 -->

</fx:Declarations>

<s:Panel width="564" height="304" verticalCenter="74" horizontalCenter="17" title="Flex Remoting示例">


<s:Rect left="0" right="0" bottom="0" height="30">

<s:fill>

<s:SolidColor color="#E2EDF7"/>

</s:fill>

</s:Rect>

<s:Button id="btnLoad" x="465" y="242" label="加载远程数据 "/>

<mx:AdvancedDataGrid id="adg1"

 designViewDataType="flat" width="562" height="241" x="0" y="0">

<mx:columns>

<mx:AdvancedDataGridColumn headerText="商品编号 " dataField="shopId"/>

<mx:AdvancedDataGridColumn headerText="商品名称 " dataField="shopName"/>

<mx:AdvancedDataGridColumn headerText="商晶单价 " dataField="price"/>

<mx:AdvancedDataGridColumn headerText="商品类别 " dataField="catalog"/>

</mx:columns>

</mx:AdvancedDataGrid>

</s:Panel>

</s:Application>

Ø 将remotingApp项目发布到Tomcat容器中,然后选中“remotingApp.mxml”,单击右键选择“Run As”à“Web应用程序”,运行Flex应用程序,结果如图5.1.9所示。

 

5.1.9 运行Flex应用

 

Ø 单击MyEclipse右上角的【MyEclipse】按钮,切换至Java应用开发视图,创建POJO类,命名为“Shoplnfo.java”。 

package com.soft.flex.pojo;

public class ShopInfo

{

private String shopId;//商品编号

private String shopName;//商品名称private double price;//商品单价

private String catalog;//商品类别

private double price;//商品价格

public ShopInfo (String shopId, String shopName, double price, String catalog) {

super();

this.shopId=shopId;

this.shopName= shopName;

this.price=price;

this.catalog=catalog;

}

public ShopInfo() {

super();

// TODO Auto-generated constructor stub

}

public String getShopId() {

return shopId;

}

public void setShopId(String shopId) {

this.shopId = shopId;

}

public String getShopName() {

return shopName;

}

public void setShopName(String shopName) {

this.shopName = shopName;

}

public String getCatalog() {

return catalog;

}

public void setCatalog(String catalog) {

this.catalog = catalog;

}

public double getPrice() {

return price;

}

public void setPrice(double price) {

this.price = price;

}

 

 

}

Ø 继续创建业务类,命名为“Service.java”,在其中定义getAllShop方法,用于从数据库中获取商品列表并返回商品信息。 

public class Service {

public List<ShopInfo> getAllShop(){

//访问数据库代码

List<ShopInfo> shops = new ArrayList<ShopInfo>();

shops.add(new ShopInfo("S001", "彩电", 1200, "家电"));

shops.add(new ShopInfo("S002", "空调", 1300, "家电"));

shops.add(new ShopInfo("S003", "牛奶", 4.5, "饮料"));

shops.add(new ShopInfo("S004", "可口可乐", 3.8, "饮料"));

return shops;

}

}

Ø 在remoting-config.xml文件中配置远程调用类Service。使用记事本打开该文件,在根节点中添加一个子节点。 

<destination id="service">

<properties>

<source>com.soft.flex.service.Service</source>

</properties>

</destination>

在remoting-config.xml文件中可以配置多个destination 每个节点代表一个远程调用类,使用id属性加以标识 其值不可重复。 Source代表class文件路径。

Ø 修改remotingApp.mxml文件代码,在其中创建RemoteObject对象,并使用该对象访问远程调用类Service.修改后的代码如下: 

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

   xmlns:s="library://ns.adobe.com/flex/spark"

   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">

<fx:Script>

<![CDATA[

import mx.controls.Alert;

import mx.rpc.events.FaultEvent;

import mx.rpc.events.ResultEvent;

//处理返回结果时间

protected function shopRemotingObject_resultHandler(event:ResultEvent):void

{

//获取结果并显示

this.adg1.dataProvider = event.result;

}


//处理访问错误异常信息

protected function shopRemotingObject_faultHandler(event:FaultEvent):void

{

//显示错误信息

Alert.show(event.fault.faultString,"错误");

}

 

 

protected function btnLoad_clickHandler(event:MouseEvent):void

{

this.shopRemotingObject.getAllShop();

}

 

]]>

</fx:Script>

<fx:Declarations>

<s:RemoteObject id="shopRemotingObject" destination="service" showBusyCursor="true"

endpoint="http://localhost:8080/remotingApp/messagebroker/amf"

result="shopRemotingObject_resultHandler(event)"

fault="shopRemotingObject_faultHandler(event)">


</s:RemoteObject>

</fx:Declarations>

<s:Panel width="564" height="304" verticalCenter="74" horizontalCenter="17" title="Flex Remoting示例">


<s:Rect left="0" right="0" bottom="0" height="30">

<s:fill>

<s:SolidColor color="#E2EDF7"/>

</s:fill>

</s:Rect>

<s:Button id="btnLoad" x="465" y="242" label="加载远程数据 " click="btnLoad_clickHandler(event)"/>

<mx:AdvancedDataGrid id="adg1"

 designViewDataType="flat" width="562" height="241" x="0" y="0">

<mx:columns>

<mx:AdvancedDataGridColumn headerText="商品编号 " dataField="shopId"/>

<mx:AdvancedDataGridColumn headerText="商品名称 " dataField="shopName"/>

<mx:AdvancedDataGridColumn headerText="商晶单价 " dataField="price"/>

<mx:AdvancedDataGridColumn headerText="商品类别 " dataField="catalog"/>

</mx:columns>

</mx:AdvancedDataGrid>

</s:Panel>

</s:Application>

Ø 重新发布remotingApp,再次运行remotingApp.mxml文件,单击“加载远程数据”按钮, Flex会调用远程Java类查询数据库的商品信息并显示出来,如图5.1.10所示。

 

5.1.10

1.3 BlazeDS的序列化机制

    为了传输对象,BlazeDS和Flex提供了客户端ActionScript对象和服务器端Java对象之间的序列化功能;对于Web Service,也提供了客户端ActionScript对象和SOAP对象之间的序列化功能。

    传输对象时,我们一般会选用AMF3来进行编码。AMF3是Adobe在Flash Player 9之后引入的一种用于序列化ActionScript对象的压缩的二进制格式。由于它非常紧凑,而且支持广泛的数据类型和复杂的对象关系,所以在企业应用中被大量使用。

    本节以AMF3编码规则为例,介绍ActionScript对象和Java对象之间的序列化机制。

    1.元标记RemoteClass和Transient

    Flex提供了两个元标记来帮助序列化。RemoteClass是修饰类的编译期的元标记,它[[RemoteClass(alias=””)]的形式定义在ActionScript类前,用于显式映射其修饰的类和远程类编译器在遇到[RemoteClass]元标记时,会在其所在应用(Application)或模块(Module)的初始化代码中插入flash.net.registerClas sAlias( aliasName,classObject)调用以注册ActionScript类及其远程别名。而Transient则是运行期元标记,修饰类的成员变量,用于表明成员变量是瞬态变量,不参与序列化。

    有两点必须注意:其一,使用[RemoteClass]修饰的ActionScript类必须在代码中被引用或使用(也就是说,不是孤立的类),否则,从Java对象无法转换到期望的ActionScript对象。编译成library的类没有此限制,因为不论其是否被引用,FlexBuilder都会编译它;其二,除了[Transient]修饰的成员变量外,非公开变量或属性、只读属性(只有get访问函数)和静态变量属性也不参与序列化,这一点对于ActionScript和Java类是一致的。

  示例5.1给出了两者的使用范例,代码第4行通过[RemoteClass]元标记显式地将自定义ActionScript静态对象Employee映射到同名的Java对象。代码第10行使用了元标记[Transient]修饰Employee的成员变量age。

  经过这两个元标记修饰后,当Flex调用远程方法传递Employee时,BlazeDS会将其转换成同名的Java对象,但age变量会被Flex序列化机制忽略,反之亦然。

 

示例5.1 Employee.as

   package  com. flexbook.blazeds

     {

             [ Bindable ]

               [ Remo teClas s ( alias = " cam. flexbook.blazeds .Employee " )  ]

    public class Employee

           {

       public var name:String;

       public var code:String;

       public var birthday:Date;

      [Transientl

     public var age:uint;

    }

 }

 

  2.从ActionScript对象到Java对象

  当Flex应用程序通过RemoteObject调用远程Java方法时,方法的参数会被自动从ActionScript对象转换成Java对象。这个过程经历了两个阶段,首先,Flash PlayerActionScript对象编码成AMF3格式,然后,BlazeDS将AMF3格式的数据流转换成Java对象。

  ActionScript中有些类型,如int、Boolean和String,与Java类型精确匹配,而uint和Number 则没有相应的Java类型与之对应。表4-1-1列出了从ActionScript对象转换到Java对象时的类型对应关系。

4-1-1  ActionScript对象转换到Java对象时的类型对应关系

ActionScript 类型 (AMF 3)

反序列化为 Java

支持的 Java 类型绑定

Array(密集)

java.util.List

java.util.Collection, Object[ ] (本机数组)

如果类型是一个接口,则会映射到下面的接口实现:

List 变为 ArrayList

SortedSet 变为 TreeSet

Set 变为 HashSet

Collection 变为 ArrayList

自定义 Collection 实现的新实例会绑定到该类型。

Array(稀疏)

java.util.Map

java.util.Map

Boolean

字符串"true""false"

java.lang.Boolean

Booleanboolean 和 String

Flash.utils.ByteArray

byte []


Flash.utils.IExternalizable

java.io.Externalizable


Date

java.util.Date

(已设置为协调世界时 (UTC) 格式)

java.util.Datejava.util.Calendarjava.sql.Timestampjava.sql.Time 和 java.sql.Date

int/uint

java.lang.Integer

java.lang.Doublejava.lang.Longjava.lang.Floatjava.lang.Integerjava.lang.Shortjava.lang.Bytejava.math.BigDecimaljava.math.BigIntegerString,以及基元类型 doublelongfloatintshort 和 byte

Null

null

基元

Number

java.lang.Double

java.lang.Doublejava.lang.Longjava.lang.Floatjava.lang.Integerjava.lang.Shortjava.lang.Bytejava.math.BigDecimaljava.math.BigIntegerString0(零)

如果发送了 null,则为基元类型 doublelongfloatintshort 和 byte

Object(泛型)

java.util.Map

如果指定了 Map 接口,则为 java.util.Map 创建一个新的 java.util.HashMap,为 java.util.SortedMap 创建一个新的 java.util.TreeMap

String

java.lang.String

java.lang.Stringjava.lang.Booleanjava.lang.Numberjava.math.BigIntegerjava.math.BigDecimalchar[]、以及任何基元数字类型

有类型对象

有类型对象

在使用 [RemoteClass] 元数据标签指定远程类名称时。Bean 类型必须具有公共的无参数构造函数。

有类型对象

undefined

null

null(对于对象)和默认值(对于基元)

XML

org.w3c.dom.Document

org.w3c.dom.Document

XMLDocument

(旧 XML 类型)

org.w3c.dom.Document

org.w3c.dom.Document

可以针对在 services-config.xml 文件中定义的任何通道启用对于 XMLDocument 类型的旧 XML 支持。此设置仅在将数据从服务器发回到客户端时很重要,它控制org.w3c.dom.Document 实例如何发送到 ActionScript

 

  当然,BlazeDS在Java对象中寻找合适的方法签名时会尝试对Java类型做出兼容的转换。比如,Flex应用在调用远程方法时传人一个int类型的参数,但远程Java对象只有一个接受参数的方法,这时,BlazeDS将尝试将这个int转换成java.lang.String,然后再调用方法。

  ActionScript中的Array允许两种方式索引元素,严格数组(strict array)使用数字作为索引,索引代表了元素的排列位置,关联数组(associative array)使用字符串作为索引,索引代表了元素的名称。一个数组中只要有一个元素使用字符串作为索引,那么它就是关联数组,这时,数组实际上退化成了ActionScript的动态对象。在严格数组中,我们把索引不是从0开始或者索引不连续的数组称为稀疏数组。关联数组通过序列化将转换成java.util.Map,稀疏数组也被转换成java.util.Map以避免传递大量null元素。

对于ActionScriptString类型,由于可以匹配的JavaString类型,因此优先转换成字符串,但如果远程Java对象中没有方法的签名能够匹配,BlazeDS将尝试将字符串转换成Boolean(如果字符串是true,false)或数值类型(如果字符串表示一个数值)

如果将ActionScriptnull 或者undefined传给远程Java方法,他将会被转化成null(如果目标类型是java.lang.Object或其子类)或转换成基本类型的默认值(如果目标类型是Java中的基本类型)

Java对象到ActionScript对象

当服务器需要返回Java对象时,BlazeDS会将Java对象编码成AMF3格式,并序列化到Flex应用端,Flex应用解析AMF3格式的流数据生成ActionScript对象。表4-1-2列出了Java对象转换成ActionScript对象的类型对应关系。

4-1-2 Java对象转换成ActionScript对象的类型对应关系。

 

Java 类型

ActionScript 类型 (AMF 3)

java.lang.String

String

java.lang.Boolean, boolean

Boolean

java.lang.Integer, int

int

如果值小于 0xF0000000 且大于 0x0FFFFFFF,则会按照 AMF 编码要求将值提升为 Number

java.lang.Short, short

int

如果 小于 0xF0000000 且大于 0x0FFFFFFF,则会将值提升为Number

java.lang.Byte, byte[]

int

如果 小于 0xF0000000 且大于 0x0FFFFFFF,则会将值提升为Number

java.lang.Byte[]

flash.utils.ByteArray

java.lang.Double, double

Number

java.lang.Long, long

Number

java.lang.Float, float

Number

java.lang.Character, char

String

java.lang.Character[], char[]

String

java. math.BigInteger

String

java.math.BigDecimal

String

java.util.Calendar

Date

日期按照协调世界时 (UTC) 时区的时间进行发送。客户端和服务器必须根据时区相应地调整时间。

java.util.Date

Date

日期按照 UTC 时区的时间进行发送。客户端和服务器必须根据时区相应地调整时间。

java.util.Collection(例如,java.util.ArrayList

mx.collections.ArrayCollection

java.lang.Object[]

Array

java.util.Map

Object(无类型)。例如,将 java.util.Map[] 转换为对象的 Array

java.util.Dictionary

Object(无类型)

org.w3c.dom.Document

XML 对象

Null

null

java.lang.Object(以前列出的类型除外)

有类型 Object

通过使用 JavaBean 内部检查规则将对象进行序列化,并且对象包括公共字段。不包括静态字段、瞬态字段、非公共字段,以及非公共 bean属性或静态 bean 属性。

 

如果没有使用[RemoteClass]标签,则转换成动态对象,否则转换成自定义的静态对象。

4.自定义序列化机制

 以上讨论的是BlazeDS的标准序列化机制。如果标准规则不能满足要求,BlazeDS还提供了扩展机制,允许编写代码自定义序列化规则。在Flex端,我们可以使目标类实现接口flash.net.IExternalizable,在Java端实现接口java.io.Externalizable。

  自定义序列化机制有很多应用场景,比如压缩数据、隐藏敏感数据等。示例5.2定义了一个DataRow类,它是所有数据行对象的基类,每个数据行都有一个唯一标示符rowID,通过rowID客户端和服务器端可以识别它们操作的对象,通常,我们期望rowID由服务器端负责生成,并且一旦分配给对象就不能被外部更改,因此它需要被定义成只读属性。而BlazeDS标准的序列化机制是不序列化只读属性的,但rowID是如此重要,以至于如果不传递给客户端,那么在客户端处理完DataRow后,服务器端就不知道是哪个DataRow对象被处理了。

  自定义序列化机制可以帮助实现我们的愿望:让DataRow实现接口IExternalizable,然后在WriteExternal和readExternal中分别向序列化流写入和从序列化流读出rowID。这样,即使我们将rowID定义成只读属性,丝毫不影响rowID的序列化。

示例5.2DataRow.as

package com.flexbook.blazeds

 {

   import flash.utils.IDataInput;

   import  flash.utils .IDataOutput ;

   import   flash.utils .IExternalizable ;

 

  [ RemoteClass ( alias = " cam. flexbook.blazeda .DataRow " ) ]

public class DataRow implemente IExternalizable

 {

  private var _rowID:Object;

  public function DataRow() {

         }

   public function get rowID():Object{

       return _rowID;

         }

   public function writeExternal(output:IDataOutput)

               output.writeObject (_rowID) ;

        }

    public function readExternal(input:IDataInput) {

                 rowID=input.readObject ( ) ,

 

 }

}

    flash.utils.IDataInput和flash.utils.IDataOutput代表了序列化的输入流和输出流,当Flex序列化对象时,会调用对象的writeExternal,并传入IDataOutput以便对象输出其属性;当Flex反序列化对象时,则调用对象的readExternal,并传入IDatalnput以便对象从流中读取其属性IDataInput和IDataOutput提供了读取和写入各种类型ActionScript对象的函数,来帮助我们序列化和反序列化。

    示例5.3DataRow对象在服务器端的定义,它与前端代码基本相似,唯一不同的是它有两个构造函数,默认构造函数用于反序列化(因为反序列化必须要有无参构造函数),:另一构造函数用于服务器端创建DataRow对象时为它指定rowID(这也是可以修改rowID的唯一的机会)。

 

示例5.3  DataRow.java



public class DataRow implements Externalizable{

 

private Object rowID,

    public  DataRow()  {

    super();

    )    

    public DataRow(Object rowID)  {

    super();

    this.rowID=rowID;

    )

    public  Object  getRowID()(

    return rowID;

    )

    public void readExternal(ObjectInput in) throws IOException,

    ClassNotFoundException {

    rowID=in.readObject();

    )

    public voicl writeExternal(ObjectOutput.ut) throws IOException  {

    out.writeObiect(rowID);

    )

    )


    如此,我们就得到了一个安全的DataRow对象,除了构造时可以为它分配rowID,其他时毫无论在服务器端还是客户端都无法对rowID进行修改。从它继承的类都可以获得这项好处,前提是服务器端的Java类和客户端的ActionScript都需要继承相应的DataRow。

1.4 BlazeDSSpring整合

如果需要BlazeDsSpring框架整合使用,是非常简单的事情,因为,SpringSourceAdobe已经合作为BlazeDS提供了Spring支持,即Spring BlazeDS Integration,关于这个项目的更多信息可以访问http://www.springsource.org/spring-flex

Spring BlazeDS Integration 是 SpringSource 的开源项目,用于整合 Spring 与 BlazeDS。不使用Spring BlazeDS Integration 同样可以整合 Spring 与 BlazeDS。但这种整合方式不自然,需要额外维护一个 BlazeDS 配置文件,Spring BlazeDS Integration 会改善这种处境。

Spring BlazeDS Integration 需要的软件环境:

Ø Java 5 或更高

Ø Spring 2.5.6 或更高

Ø BlazeDS 3.2 或更高

Spring BlazeDS Integration 特征

Ø MessageBrokerBlazeDS 的核心组件)被配置为 Spring 管理的 Bean

Ø Flex 客户端发出的 HTTP 消息通过 Spring 的 DispatcherServlet 路由给 MessageBroker

Ø Remote objects 以 Spring 的方式配置在 Spring 配置文件内

 

下面我们演示BlazeDSSpring的整合。

1准备所需 jar 

下载 Spring Framework dependenciesSpring BlazeDS Integration解压备用,在项目中添加Spring支持,并将以下 部分 jar 包拷贝到项目的 lib 下:

Ø Spring Framework dependencies

org.aopalliance 内的 com.springsource.org.aopalliance-1.0.0.jar

edu.emory.mathcs.backport 内的 com.springsource.edu.emory.mathcs.backport-3.0.0.jar

net.sourceforge.cglib 内的 com.springsource.net.sf.cglib-2.2.0.jar

Ø Spring BlazeDS Integration

org.springframework.flex-1.0.3.RELEASE.jar

2):修改 web.xml 文件

 web.xml 内所有 Flex 相关配置删除掉,添加以下内容(改用 Spring web 应用的前端控制器处理所有应用请求)

 

<servlet>

  <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>

  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

  <init-param>

    <param-name>contextConfigLocation</param-name>

    <param-value>/WEB-INF/web-application-config.xml</param-value>

  </init-param>

  <load-on-startup>1</load-on-startup>

</servlet>

 

<servlet-mapping>

  <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>

  <url-pattern>/messagebroker/*</url-pattern>

</servlet-mapping>

3):配置 web-application-config.xml

1)创建应用上下文配置文件 web-application-config.xml

 

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

 

</beans>

2)为了使用 Spring BlazeDS Integration 的 tag,增加命名空间

 

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:flex="http://www.springframework.org/schema/flex"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd       http://www.springframework.org/schema/flex       http://www.springframework.org/schema/flex/spring-flex-1.0.xsd">

 

</beans>

3)为了把请求路由给 MessageBroker,添加以下 tag

 

<flex:message-broker />

4)定义 Bean,并用 remoting-destination tag 把它暴露给 Flex

 

<bean id="employeeServiceDest" class="com.sample.EmployeeService">

  <flex:remoting-destination />

</bean>

 

至此BlazeDSSpring的整合就完成了。

 

1.5 BlazeDS的消息服务

BlazeDS消息服务(Message Service )提供发布(publish)/订阅(subscribe)机制,允许 Flex 应用程序发布消息、订阅消息终端(messaging destination),从而实现实时数据的推动和协作传送。

 

1Message Service

 

Message Service 提供发布(publish)/订阅(subscribe)机制允许Flex 应用 程序发布消息、订阅消息终端(messaging destination),从而实现数据的实时 推动和协作传送。

消息终端在messaging-config.xml配置,其中频道(channel)是其关键元素, 它用来实现客户端和服务器端交换数据。使用BlazeDS,消息终端通常用作 streaming频道或者polling频道。

使用streaming频道,服务器端会一直响应HTTP请求直到该频道连接被关闭, 它允许服务器向客户端不断传送大量的数据。因为HTTP连接是独一无二的,这实 现数据的双向传送,每个streaming AMF或者HTTP频道事实上需要两个浏览器 HTTP连接, 一个连接需要不断处理服务器端与频道紧密相关的客户端的响应。 另外需要一个短暂连接,只有当数据需要传送到服务器时,它才脱离浏览器连接 池;当短暂连接不再需要时,它立即被释放回浏览器连接池。

polling频道可以通过简单的时间间隔或者使用服务器等待来配置,如果数据 不马上可用 (长轮循)的话。另外,每次轮循响应完成请求。默认下浏览器HTTP 1.1的连接是持续的,浏览器轮循已有的连接,发送并发的轮循请求,以此来减 轻轮循的开销。

当需要准实时通信时,streaming 频道是最好选择。

 

2IE 与 Firefox浏览器下的不同

浏览器对每个session都有连接数限制。不同的浏览器,连接最大数以及对 session的处理方式都不一样。

IE中每个session的最大连接数为2。 但如果从开始菜单或快捷方式打开多个 IE实例,每个IE实例开启不同的进程并拥有各自session。另外,如果我们通过 CTRL+N 开启对已有的IE实例一个新的IE窗口,该窗口将与创建它的IE实例共用 一个session 。也就是说,如果程序实例开启不同的进程,我们可以通过HTTP streaming建立不限量应用取得服务器端数据;如果通过CTRL+N开启多个窗口, 每个session最多建立2个连接。

Firefox中每个session最多建立8个连接。如果从开始菜单或快捷方式打开多 个Firefox实例,所有实例开启使用同一进程并共用一个session。既然浏览器对 普通的HTTP请求通常只需要一个连接, 理论上我们可以最多可以建立7HTTP streaming连接。

 

3messaging-config.xml

另外,如果每个session到达最大连接数,使用streaming channel连接到服务器的下一次尝试将失败并抛出以下异常:

Endpoint with id 'my-streaming-amf' cannot grant streaming connection to FlexClient with id 'D640B86F-6B1D-92DF- 8288-1B737A371AFE' because max-streaming-connections-per-session limit of '1' has been reached

不过,BlazeDS提供一种优雅的退后机制来处理这种情况:

客户端始终会尝试使用频道表(messaging-config.xml中为服务终端定义中的第一个频道来连接。如果该连接失败客户端将自动退后到频道表中的下一频道。我们可以为所有的服务终端定义了如下默认的ChannelSet

 

<default-channels>

<channel ref="my-streaming-amf"/>

<channel ref="my-polling-amf"/>

</default-channels>

 

也就是说,客户端应用会首先尝试使用streaming channel连接,如果连接失 败会使用polling channel

 

在客户端,Flex提供了 ProducerConsumer这两个组件,让你用来向目标地址发送或订阅消息。如果要订阅消息,你就使用Consumer类的 subscribe()方法。当有消息发送到你订阅了的目标地址时,Consumer上就会触发message事件。

示例5.4

客户端代码:

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

   xmlns:s="library://ns.adobe.com/flex/spark"

   creationComplete="consumer.subscribe();"

   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">

<fx:Script>

<![CDATA[

import mx.controls.Alert;

import mx.messaging.events.MessageFaultEvent;

import mx.messaging.messages.AsyncMessage;

import mx.messaging.messages.IMessage;

private function send():void  

{   

   var message:IMessage = new AsyncMessage();   

   message.body.chatMessage = msg.text+consumer.clientId;   

    producer.send(message);   

    msg.text = "";   

       

  }   

          

   private function messageHandler(message:IMessage):void  

   {   

    log.text += message.body.chatMessage + "\n";    

   }   

 

 

protected function consumer_faultHandler(event:MessageFaultEvent):void

{

Alert.show(event.faultDetail);

}

 

 

protected function producer_faultHandler(event:MessageFaultEvent):void

{

Alert.show(event.faultDetail);

}

 

]]>

</fx:Script>

<fx:Declarations>

<mx:ChannelSet id="cs">   

  <mx:StreamingAMFChannel url="http://localhost:8400/MsgService/messagebroker/streamingamf"/>   


  </mx:ChannelSet>   

  <mx:Producer id="producer"  fault="producer_faultHandler(event)" destination="chat" channelSet="{cs}"/>   

  <mx:Consumer id="consumer" destination="chat" channelSet="{cs}" message="messageHandler(event.message)" fault="consumer_faultHandler(event)"/>   

 

</fx:Declarations>


<s:Panel title="Chat Test!"   x="20" y="19" width="518" height="295">   

  <s:TextArea id="log" x="19" y="11" width="473" height="166"/>   

     

  <s:TextInput id="msg" x="19" y="191" width="377" height="46" enter="send()"/>   

  <s:Button x="411" y="192" label="发送消息" height="43" width="77" click="send()"/>   

    

 </s:Panel>   

 

</s:Application>

 

服务器端services-config.xml定义Streaming通道:

<?xml version="1.0" encoding="UTF-8"?>

<service id="message-service"

    class="flex.messaging.services.MessageService">

 

    <adapters>

        <adapter-definition id="actionscript" class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" />

       <adapter-definition id="jms" class="flex.messaging.services.messaging.adapters.JMSAdapter"/>

    </adapters>

 



    <!--   <default-channels>

        <channel ref="my-polling-amf"/>

    </default-channels>-->

<destination id="chat">   

          

        <properties>   

           <network>   

                <session-timeout>0</session-timeout>   

            </network>   

            <server>   

               <max-cache-size>1000</max-cache-size>   

                <message-time-to-live>0</message-time-to-live>   

                <durable>false</durable>   

           </server>   

        </properties>   

        <channels>   

        <channel ref="my-streaming-amf" />   

        </channels>   

    </destination>   

 

</service>

 

服务器端messaging-config.xm中定义目标并指定通道:

<?xml version="1.0" encoding="UTF-8"?>

<services-config>

 

    <services>

        <service-include file-path="remoting-config.xml" />

        <service-include file-path="proxy-config.xml" />

        <service-include file-path="messaging-config.xml" />        

   

 

     

      </services>

    <security>

        <login-command class="flex.messaging.security.TomcatLoginCommand" server="Tomcat"/>

        <!-- Uncomment the correct app server

        <login-command class="flex.messaging.security.TomcatLoginCommand" server="JBoss">

<login-command class="flex.messaging.security.JRunLoginCommand" server="JRun"/>        

        <login-command class="flex.messaging.security.WeblogicLoginCommand" server="Weblogic"/>

        <login-command class="flex.messaging.security.WebSphereLoginCommand" server="WebSphere"/>

        -->

 

        <!--

        <security-constraint id="basic-read-access">

            <auth-method>Basic</auth-method>

            <roles>

                <role>guests</role>

                <role>accountants</role>

                <role>employees</role>

                <role>managers</role>

            </roles>

        </security-constraint>

         -->

    </security>

 

    <channels>

 

 <channel-definition id="my-streaming-amf" class="mx.messaging.channels.StreamingAMFChannel">   

            <endpoint url="http://localhost:8400/MsgService/messagebroker/streamingamf" class="flex.messaging.endpoints.StreamingAMFEndpoint"/>   

            <properties>   

               <idle-timeout-minutes>0</idle-timeout-minutes>   

                <max-streaming-clients>50</max-streaming-clients>   

                <server-to-client-heartbeat-millis>5000</server-to-client-heartbeat-millis>   

               <user-agent-settings>   

                    <user-agent match-on="MSIE" kickstart-bytes="2048" max-streaming-connections-per-session="1"/>   

                   <user-agent match-on="Firefox" kickstart-bytes="2048" max-streaming-connections-per-session="1"/>   

                </user-agent-settings>   

           </properties>   

        </channel-definition>

        <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">

            <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>

        </channel-definition>

 

        <channel-definition id="my-secure-amf" class="mx.messaging.channels.SecureAMFChannel">

            <endpoint url="https://{server.name}:{server.port}/{context.root}/messagebroker/amfsecure" class="flex.messaging.endpoints.SecureAMFEndpoint"/>

            <properties>

                <add-no-cache-headers>false</add-no-cache-headers>

            </properties>

        </channel-definition>

 

        <channel-definition id="my-polling-amf" class="mx.messaging.channels.AMFChannel">

            <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amfpolling" class="flex.messaging.endpoints.AMFEndpoint"/>

            <properties>

                <polling-enabled>true</polling-enabled>

                <polling-interval-seconds>4</polling-interval-seconds>

            </properties>

        </channel-definition>

 

      

        <channel-definition id="my-http" class="mx.messaging.channels.HTTPChannel">

            <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/http" class="flex.messaging.endpoints.HTTPEndpoint"/>

        </channel-definition>

  <!--

        <channel-definition id="my-secure-http" class="mx.messaging.channels.SecureHTTPChannel">

            <endpoint url="https://{server.name}:{server.port}/{context.root}/messagebroker/httpsecure" class="flex.messaging.endpoints.SecureHTTPEndpoint"/>

            <properties>

                <add-no-cache-headers>false</add-no-cache-headers>

            </properties>

        </channel-definition>

        -->

    </channels>

 

    <logging>

        <target class="flex.messaging.log.ConsoleTarget" level="Error">

            <properties>

                <prefix>[BlazeDS] </prefix>

                <includeDate>false</includeDate>

                <includeTime>false</includeTime>

                <includeLevel>false</includeLevel>

                <includeCategory>false</includeCategory>

            </properties>

            <filters>

                <pattern>Endpoint.*</pattern>

                <pattern>Service.*</pattern>

                <pattern>Configuration</pattern>

            </filters>

        </target>

    </logging>

 

    <system>

        <redeploy>

            <enabled>false</enabled>

            <!--

            <watch-interval>20</watch-interval>

            <watch-file>{context.root}/WEB-INF/flex/services-config.xml</watch-file>

            <watch-file>{context.root}/WEB-INF/flex/proxy-config.xml</watch-file>

            <watch-file>{context.root}/WEB-INF/flex/remoting-config.xml</watch-file>

            <watch-file>{context.root}/WEB-INF/flex/messaging-config.xml</watch-file>

            <watch-file>{context.root}/WEB-INF/flex/data-management-config.xml</watch-file>

            <touch-file>{context.root}/WEB-INF/web.xml</touch-file>

             -->

        </redeploy>

    </system>

 

</services-config>

运行应用效果如图5.1.11所示,轻松实现了数据的推送:

 

 

5.1.11 Flex数据推送


任务实训部分 


 

实训任务1:使用HttpServcie方式与后台通信

训练技能点

HttpServcie

需求说明

使用HttpService对象开发Flex应用程序 按条件查询数据库中某张表的数据并显示在表格中。

实现思路

1)创建Flex项目,将此项目的服务器技术选择为J2EE服务器(无需使用远程对象访问服务)。

2)切换到MyEclipese java 开发视图,创建一个POJO类用于描述奥运会各个国家获得的奖牌情况。

package com.soft.flex.flex4sj.pojo;

 

public class Cup {

private int id;

//国家代号

private String countryId;

//国家名称

private String countryName;

//金牌数

private int goldMedal;

//银牌数

private int silverMedal;

//铜牌数

private int bronzeMedal;

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getCountryId() {

return countryId;

}

public void setCountryId(String countryId) {

this.countryId = countryId;

}

public String getCountryName() {

return countryName;

}

public void setCountryName(String countryName) {

this.countryName = countryName;

}

public int getGoldMedal() {

return goldMedal;

}

public void setGoldMedal(int goldMedal) {

this.goldMedal = goldMedal;

}

public int getSilverMedal() {

return silverMedal;

}

public void setSilverMedal(int silverMedal) {

this.silverMedal = silverMedal;

}

public int getBronzeMedal() {

return bronzeMedal;

}

public void setBronzeMedal(int bronzeMedal) {

this.bronzeMedal = bronzeMedal;

}

public Cup(String countryId, String countryName, int goldMedal,

int silverMedal, int bronzeMedal) {

super();

this.countryId = countryId;

this.countryName = countryName;

this.goldMedal = goldMedal;

this.silverMedal = silverMedal;

this.bronzeMedal = bronzeMedal;

}

public Cup() {

super();

// TODO Auto-generated constructor stub

}


}

(3)创建业务类,在该类 中定义根据国家查询获取奖牌情况的方法。

package com.soft.flex.flex4sj.service;

 

 

import java.util.*;

 

import com.soft.flex.flex4sj.pojo.Cup;

 

 public class CupService {

private List<Cup> cupList;

//模拟数据库数据

public CupService(){

cupList  = new ArrayList();

Cup cup1 = new Cup("china", "中国",30 ,20 ,10 );

Cup cup2 = new Cup("america", "美国",20 ,23 ,12 );

Cup cup3 = new Cup("japan", "日本",25 ,27 ,15 );

Cup cup4 = new Cup("france", "法国",10 ,18 ,20 );

Cup cup5 = new Cup("russia", "俄罗斯",16 ,30,25 );

Cup cup6 = new Cup("singapore", "新加坡",12 ,25 ,18 );

cupList.add( cup1);

cupList.add( cup2);

cupList.add( cup3);

cupList.add( cup4);

cupList.add( cup5);

cupList.add( cup6);

}

public List getAll(){



return cupList;



}

public Cup getCupByCountryId(String countryId){

Cup c = null;

for(Cup cup : cupList){


if(countryId.equals(cup.getCountryId())){

c = cup;

break;

}

}

return c;



 

}

 


 

}

 

(4)创建servlet 路径为/query, servlet根据传入的cid 调用业务类获取结果,并转化为xml格式返回。

public class QueryServlet extends HttpServlet {

 


public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doPost(request, response);

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

 

response.setContentType("text/html;charset=utf-8");

PrintWriter out = response.getWriter();

//构造xml头标记

String xml="<?xml version=\"1.0\" encoding=\"utf-8\"?><cups>";

     String method = request.getParameter("method");

     CupService service = new CupService();

     //如果是查询所有

     if("all".equals(method)){

     List<Cup> list = service.getAll();

        

        

        

         for(Cup cup : list){

        

         String cid = cup.getCountryId();

         String cname = cup.getCountryName();

         int gm = cup.getGoldMedal();

         int sm = cup.getSilverMedal();

         int bm = cup.getBronzeMedal();

         //构造xml节点

         xml += "<cup countryId='"+cid+"' countryName='"+cname+"' goldMedal='"+gm+"' silverMedal='"+sm+"' bronzeMedal='"+bm+"'/>";

        

        

         }

    

     }else{

     String countryId =  request.getParameter("cid");

     Cup cup = service.getCupByCountryId(countryId);

     String cid = cup.getCountryId();

     String cname = cup.getCountryName();

     int gm = cup.getGoldMedal();

     int sm = cup.getSilverMedal();

     int bm = cup.getBronzeMedal();

    

     xml += "<cup countryId='"+cid+"' countryName='"+cname+"' goldMedal='"+gm+"' silverMedal='"+sm+"' bronzeMedal='"+bm+"'/>";

    

    

     }

    

    

    

    

    

     xml+="</cups>";

     //输出结尾标志

     out.print(xml);

out.flush();

out.close();

}

 

}

 

(5)创建MXML界面,通过HttpService对象访问servlet 并获取查询结果。

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

   xmlns:s="library://ns.adobe.com/flex/spark"

   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"

   initialize="application1_initializeHandler(event)"

   >

<fx:Script>

<![CDATA[

import mx.controls.Alert;

import mx.events.FlexEvent;

import mx.rpc.events.FaultEvent;

import mx.rpc.events.ResultEvent;


import spark.events.IndexChangeEvent;

private var flag:int;

protected function application1_initializeHandler(event:FlexEvent):void

{

this.flag=0;

this.myhttp.url = "/sj41/query?method=all&cid=all";

this.myhttp.send();

}

 

 

protected function myhttp_resultHandler(event:ResultEvent):void

{


//如果是初始化时返回的结果

if(flag==0){

this.ddl.dataProvider=event.result.cups.cup;

this.ddl.labelField = "countryName";

this.adg1.dataProvider=event.result.cups.cup;

}

else{//如果是选择下拉列表返回的结果

this.adg1.dataProvider=event.result.cups.cup;

}

}

 

 

protected function myhttp_faultHandler(event:FaultEvent):void

{

Alert.show(event.fault.faultString);

}

 

 

protected function ddl_changeHandler(event:IndexChangeEvent):void

{

var cid:String = this.ddl.selectedItem.countryId;

this.flag=1;

this.myhttp.url = "/sj41/query?method=getById&cid="+cid;

this.myhttp.send();

}

 

]]>

</fx:Script>

<fx:Declarations>

<s:HTTPService id="myhttp"  showBusyCursor="true" result="myhttp_resultHandler(event)" fault="myhttp_faultHandler(event)"/>

</fx:Declarations>

<s:Panel width="557" height="376" title="使用HttpService 与后台通信" horizontalCenter="0" verticalCenter="0">

<mx:AdvancedDataGrid x="2" y="9" id="adg1" designViewDataType="flat" width="545" height="274">

<mx:columns>

<mx:AdvancedDataGridColumn headerText="代号" dataField="countryId"/>

<mx:AdvancedDataGridColumn headerText="国家" dataField="countryName"/>

<mx:AdvancedDataGridColumn headerText="金牌数" dataField="goldMedal"/>

<mx:AdvancedDataGridColumn headerText="银牌数" dataField="silverMedal"/>

 

<mx:AdvancedDataGridColumn headerText="铜牌数" dataField="bronzeMedal"/>

 

</mx:columns>

</mx:AdvancedDataGrid>

<s:Label x="216" y="305" text="选择国家:" height="23" verticalAlign="middle"/>

 


<s:Button x="475" y="305" label="显示全部" click="application1_initializeHandler(event as FlexEvent)"/>

<s:DropDownList x="306" y="305" id="ddl" prompt="请选择国家" change="ddl_changeHandler(event)"></s:DropDownList>

</s:Panel>

</s:Application>

 

(6)运行应用程序,效果如图5.2.1所示。

 

5.2.1 HttpService 示例

实训任务2:使用RemotingObject 与后台通信

训练技能点

RemotingObject

需求说明

使用RemotingObject 重构任务1

实现思路:

(1)创建Flex项目,将此项目的服务器技术选择为J2EE服务器(使用远程对象访问服务)。 如图5.2.2所示。

 

5.2.2 创建Flex项目

2)修改WebRoot/WEB-INFO/flex/remoting-config.xml,配置业务类

<?xml version="1.0" encoding="UTF-8"?>

<service id="remoting-service"

    class="flex.messaging.services.RemotingService">

 

    <adapters>

        <adapter-definition id="java-object" class="flex.messaging.services.remoting.adapters.JavaAdapter" default="true"/>

    </adapters>

 

    <default-channels>

        <channel ref="my-amf"/>

    </default-channels>

<destination id="service">

<properties>

<source>com.soft.flex.flex4sj.service.CupService</source>

</properties>

</destination>

</service> 

(1)修改MXML应用程序 添加RemotingObject对象

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

   xmlns:s="library://ns.adobe.com/flex/spark"

   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"

   initialize="application1_initializeHandler(event)"

   >

<fx:Script>

<![CDATA[

import mx.collections.IList;

import mx.controls.Alert;

import mx.events.FlexEvent;

import mx.rpc.events.FaultEvent;

import mx.rpc.events.ResultEvent;


import spark.events.IndexChangeEvent;

private var flag:int;

protected function application1_initializeHandler(event:FlexEvent):void

{

this.flag=0;

this.myremoting.getAll();

}

 

 


 

 

protected function ddl_changeHandler(event:IndexChangeEvent):void

{

var cid:String = this.ddl.selectedItem.countryId;

this.flag=1;

this.myremoting.getCupByCountryId(cid);

}

 

 

protected function myremoting_resultHandler1(event:ResultEvent):void

{


this.ddl.dataProvider=event.result as IList;

this.ddl.labelField = "countryName";

this.adg1.dataProvider=event.result;



}

 

protected function myremoting_resultHandler2(event:ResultEvent):void

{


this.adg1.dataProvider=event.result;


}

protected function myremoting_faultHandler(event:FaultEvent):void

{

Alert.show(event.fault.faultString);

}

 

]]>

</fx:Script>

<fx:Declarations>

<s:RemoteObject id="myremoting" showBusyCursor="true" destination="service"

endpoint="http://localhost:8080/sj42/messagebroker/amf"

fault="myremoting_faultHandler(event)"

>

<s:method name="getAll" result="myremoting_resultHandler1(event)" />

<s:method name="getCupByCountryId" result="myremoting_resultHandler2(event)"/>

</s:RemoteObject>

</fx:Declarations>

<s:Panel width="557" height="376" title="使用HttpService 与后台通信" horizontalCenter="0" verticalCenter="0">

<mx:AdvancedDataGrid x="2" y="9" id="adg1" designViewDataType="flat" width="545" height="274">

<mx:columns>

<mx:AdvancedDataGridColumn headerText="代号" dataField="countryId"/>

<mx:AdvancedDataGridColumn headerText="国家" dataField="countryName"/>

<mx:AdvancedDataGridColumn headerText="金牌数" dataField="goldMedal"/>

<mx:AdvancedDataGridColumn headerText="银牌数" dataField="silverMedal"/>

 

<mx:AdvancedDataGridColumn headerText="铜牌数" dataField="bronzeMedal"/>

 

</mx:columns>

</mx:AdvancedDataGrid>

<s:Label x="216" y="305" text="选择国家:" height="23" verticalAlign="middle"/>

 


<s:Button x="475" y="305" label="显示全部" click="application1_initializeHandler(event as FlexEvent)"/>

<s:DropDownList x="306" y="305" id="ddl" prompt="请选择国家" change="ddl_changeHandler(event)"></s:DropDownList>

</s:Panel>

</s:Application>

 

 

运行应用,效果如图5.2.1所示。

 

 

实训任务3RemotingObject 整合Hibernate Spring

训练技能点

Ø RemotingObject

Ø 整合Spring框架。

需求说明

使用RemotingObject 整合Hibernate Spring 重构任务1

实现思路:

1创建Flex项目,将此项目的服务器技术选择为J2EE服务器(使用远程对象访问服务)

2)创建数据库表tb_cup 表字段与实体类属性对应 如图5.2.3所示。

 

5.2.2 tb_Cup

3)切换到MyEclipes视图,分别添加hibernate支持和spring支持,并使用逆向工程生成视图类,映射文件等。

4创建业务类,在该类 中定义根据国家查询获取奖牌情况的方法。

package com.soft.flex.flex4sj.service;

 

import java.util.List;

 

import com.soft.flex.flex4sj.dao.Cup;

import com.soft.flex.flex4sj.dao.CupDao;

 

public class CupService {

private CupDao dao;

 

public List<Cup> getAll(){


return dao.findAll();

}

public List<Cup> getCupByCountryId(String cid){


return dao.findByCountryId(cid);

}

public CupDao getDao() {

return dao;

}

 

public void setDao(CupDao dao) {

this.dao = dao;

}


}

 

(5)添加整合Spring框架的响应jar包 并在applicationContext.xml中配置业务类。

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:flex="http://www.springframework.org/schema/flex"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xsi:schemaLocation="http://www.springframework.org/schema/beans

         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

         http://www.springframework.org/schema/flex       

         http://www.springframework.org/schema/flex/spring-flex-1.0.xsd">

         <flex:message-broker />

<bean id="service" class="com.soft.flex.flex4sj.service.CupService">

  <flex:remoting-destination />

  <property name="dao" ref="CupDAO"></property>

</bean>

<!--其他配置省略-->

</beans>

(6)修改工程的web.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>

<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<display-name>sj43</display-name>

 

<context-param>

<param-name>flex.class.path</param-name>

<param-value>/WEB-INF/flex/hotfixes,/WEB-INF/flex/jars</param-value>

</context-param>

 

<!-- Http Flex Session attribute and binding listener support -->

<listener>

<listener-class>flex.messaging.HttpFlexSession</listener-class>

</listener>

 

<!-- MessageBroker Servlet -->

<servlet>

  <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>

  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

  <init-param>

    <param-name>contextConfigLocation</param-name>

    <param-value>classpath:applicationContext.xml</param-value>

  </init-param>

  <load-on-startup>1</load-on-startup>

</servlet>

 

<servlet-mapping>

  <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>

  <url-pattern>/messagebroker/*</url-pattern>

</servlet-mapping>

<welcome-file-list>

<welcome-file>index.html</welcome-file>

<welcome-file>index.htm</welcome-file>

<welcome-file>index.jsp</welcome-file>

<welcome-file>default.html</welcome-file>

<welcome-file>default.htm</welcome-file>

<welcome-file>default.jsp</welcome-file>

</welcome-file-list>

 


</web-app>

(7)修改MXML代码如下:

<s:RemoteObject id="myremoting" showBusyCursor="true" destination="service"

endpoint="http://localhost:8080/sj43/messagebroker/amf"


fault="myremoting_faultHandler(event)"

>

其中destination=service” service要与applicationContext.xml中业务beanid一致。

运行应用程序,效果如图5.2.1.所示(注意要在服务器中将重复的cglib.jar删去)

实训任务4:实现分页

训练技能点

Ø RemotingObject

Ø 整合Spring框架。

需求说明

在任务3的基础上实现分页功能。

实现步骤:

(1)切换到MyEclipse视图 创建Page.java用来封装分页数据。

import java.util.List;

 

public class Page {

private List data;

private int currentPage;

private int totalPage;

private int pageSize;

private int totalClum;

public List getData() {

return data;

}


public void setData(List data) {

this.data = data;

}

public int getCurrentPage() {

return currentPage;

}

public void setCurrentPage(int currentPage) {

this.currentPage = currentPage;

}

public int getTotalPage() {

return totalPage;

}

public void setTotalPage(int totalPage) {

this.totalPage = totalPage;

}

public int getPageSize() {

return pageSize;

}

public void setPageSize(int pageSize) {

this.pageSize = pageSize;

}

public int getTotalClum() {

return totalClum;

}

public void setTotalClum(int totalClum) {

this.totalClum = totalClum;

this.totalPage=( totalClum%pageSize==0  ?totalClum/pageSize:totalClum/pageSize+1);

 

}


}

 

(2)dao类中添加分页查询的方法

public List findByPage(Page page) {

      

        String hql = "from Cup";

        try {

         Session session = getSession();

         Query query = session.createQuery(hql);

         query.setFirstResult((page.getCurrentPage()-1)*page.getPageSize());

         query.setMaxResults(page.getPageSize());

         List list = query.list();

         releaseSession(session);

         return list;

           

        } catch (RuntimeException re) {

            log.error("delete failed", re);

            throw re;

        }

    }

public int count() {

        log.debug("deleting User instance");

        String hql = "select count(cup) from Cup as cup";

        try {

         Session session = getSession();

         Query query = session.createQuery(hql);

        

         long l = (Long)query.uniqueResult();

         return (int)l;

           

        } catch (RuntimeException re) {

            log.error("delete failed", re);

            throw re;

        }

    }

(3)service类中添加相应的方法。

public Page findByPage(Page page){


List data= dao.findByPage(page);

int count = dao.count();

page.setData(data);

page.setTotalClum(count);

return page;

}

 

(4)切换回Flash视图 开发与JavaPage类对应的as类。

package com.oa.vo

{

import mx.collections.ArrayCollection;

[RemoteClass(alias="com.soft.flex.flex4sj.dao.Page")]

public class Page

{

public function Page()

{

}

public var data :ArrayCollection;

public var  currentPage:int;

public var  totalPage:int;

public var  pageSize:int;

public var  totalClum:int;


}

}

 

 

(5)修改主程序的MXML文件 添加分页栏 。

<?xml version="1.0" encoding="utf-8"?>

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

   xmlns:s="library://ns.adobe.com/flex/spark"

   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"

   initialize="application1_initializeHandler(event)"

    xmlns:ns1="*">

<fx:Script>

<![CDATA[

import com.oa.vo.Page;


import mx.collections.IList;

import mx.controls.Alert;

import mx.events.FlexEvent;

import mx.rpc.events.FaultEvent;

import mx.rpc.events.ResultEvent;


import spark.events.IndexChangeEvent;

[Bindable]

private var pageData:Page;

public  function loadData(currentPage:int):void{


var page:Page = new Page();

page.currentPage=currentPage;

page.pageSize=this.setPageSize.selectedItem.data;

this.myremoting.findByPage(page);

}

protected function application1_initializeHandler(event:FlexEvent):void

{


loadData(1);

}






protected function ddl_changeHandler(event:IndexChangeEvent):void

{

var cid:String = this.ddl.selectedItem.countryId;


this.myremoting.getCupByCountryId(cid);

}



protected function myremoting_resultHandler1(event:ResultEvent):void

{


 pageData =Page( event.result) ;

Alert.show(pageData.currentPage+'c');

Alert.show(pageData.totalPage+'t');

this.ddl.dataProvider=pageData.data;

this.ddl.labelField = "countryName";

this.adg1.dataProvider=pageData.data;



}


protected function myremoting_resultHandler2(event:ResultEvent):void

{


this.adg1.dataProvider=event.result;


}

protected function myremoting_faultHandler(event:FaultEvent):void

{

Alert.show(event.fault.toString());

}


]]>

</fx:Script>

<fx:Declarations>

<s:RemoteObject id="myremoting" showBusyCursor="true" destination="service"

endpoint="http://localhost:8080/sj43/messagebroker/amf"


fault="myremoting_faultHandler(event)"

>

<s:method name="findByPage" result="myremoting_resultHandler1(event)" />

<s:method name="getCupByCountryId" result="myremoting_resultHandler2(event)"/>

</s:RemoteObject>

</fx:Declarations>

<s:Panel width="741" height="427" title="使用HttpService 与后台通信" horizontalCenter="0" verticalCenter="25">

<mx:AdvancedDataGrid x="2" y="9" id="adg1" designViewDataType="flat" width="727" height="274">

<mx:columns>

<mx:AdvancedDataGridColumn headerText="代号" dataField="countryId"/>

<mx:AdvancedDataGridColumn headerText="国家" dataField="countryName"/>

<mx:AdvancedDataGridColumn headerText="金牌数" dataField="goldMedal"/>

<mx:AdvancedDataGridColumn headerText="银牌数" dataField="silverMedal"/>


<mx:AdvancedDataGridColumn headerText="铜牌数" dataField="bronzeMedal"/>


</mx:columns>

</mx:AdvancedDataGrid>

<s:Label x="215" y="361" text="选择国家:" height="23" verticalAlign="middle"/>



<s:Button x="475" y="361" label="显示全部" click="application1_initializeHandler(event as FlexEvent)"/>

<s:DropDownList x="306" y="361" id="ddl" prompt="请选择国家" change="ddl_changeHandler(event)"></s:DropDownList>

<!--以下为分页栏-->

<mx:HBox cornerRadius="0" borderStyle="solid" horizontalAlign="left" verticalAlign="middle" width="722" x="7" y="305" height="27">


<mx:Text fontSize="12" text="{' '+pageData.currentPage+'/'+pageData.totalPage+''+' '+pageData.totalClum+'条记录'}"/>


<mx:LinkButton id="lbtnFirst" label="首页"  click="loadData(1)"  enabled="{lbtnPrevious.enabled}" fontSize="12"/>


<mx:LinkButton id="lbtnPrevious" label="上一页" click="loadData(pageData.currentPage-1)"   enabled="{pageData.currentPage!=1?true:false}"  fontSize="12"/>


<mx:LinkButton id="lbtnNext" label="下一页"   click="loadData(pageData.currentPage+1)" enabled="{pageData.totalPage>=(pageData.currentPage+1)?true:false}"  fontSize="12"/>


<mx:LinkButton id="lbtnLast" label="尾页" click="loadData(pageData.totalPage)" enabled="{lbtnNext.enabled}" fontSize="12"/>


<mx:Label   text="每页显示:"/>

<mx:ComboBox id="setPageSize"  width="71" change="loadData(1)">


<mx:dataProvider>

<mx:ArrayList  >



<fx:Object label="5" data="5" />                                                                                                         

<fx:Object label="10" data="10" />

<fx:Object label="20" data="20" />    

</mx:ArrayList>

</mx:dataProvider>

</mx:ComboBox>

<mx:Label   text=""/>


<mx:NumericStepper id="nsPageNum" stepSize="1" minimum="1" maximum="{pageData.totalPage}"  enabled="{lbtnJump.enabled}" cornerRadius="0" width="54"/>


<mx:LinkButton id="lbtnJump" label="跳转"  click="loadData(nsPageNum.value)" enabled="{pageData.totalPage>1?true:false}"  fontSize="12"/>


</mx:HBox>

</s:Panel>

</s:Application>

 

6)运行应用程序,效果如图5.2.4所示。

 

5.2.4  分页

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

巩固练习


选择题

1.  Flex与外部进行数据通信的方式有()

A.  HTTPService

B.  WebService

C.  Remoting

D.  HttpRequest

2.  以下关于FlexRemoting数据通信方式的说法,正确的是()

A.  Remoting使用AMF二进制信息格式化传递数据。

B.  Flex应用中使用Remoting 技术需要有第三方软件支持。

C.  数据量越大,Remoting方式传输效率越高。

D.  Remoting不支持序列化与反序列化。

3.  以下关于remoting-config.xml文件配置信息的描述 正确的是()

A.  使用destination节点配置远程调用类的标示。

B.  Source节点代表远程调用类的class文件路径。

C.  一个remoting-config.xml文件只允许配置一个destination节点。

D.  一个remoting-config.xml文件只允许配置多个destination节点。

简答题

1)什么Remoting数据通信技术?

操作题

开发一个WebService ,用于查询Oracle数据库中的商品信息表,并返回结果。然后通过FlexWebService组件调用webservice,将获取到的结果显示在表格组件中。