Flex与外部的数据通信

视频课: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组件的例子应用:

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

   

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

      useProxy="false" />

   

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

       

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

           

              

              

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

           

       

       

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

       

   

这个例子的运行需要能够访问互联网,在本例中通过调用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组件的例子应用。  

layout="absolute"

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

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

mxna2.cfc?wsdl"

     useProxy="false">

      

         

            30

             {cbxNumPosts.value}

         

     

    title="Most Popular Posts">

    

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

       

       

       

    

    

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

dataField="postTitle"/>

width="75"/>

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

 

  在这个例子中,通过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对象的使用:

 

    

        

            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');

            }

        ]]>

    

    

 

在上面的代码中首先看一下函数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文件,向其中添加以下代码: 

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

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

示例">

加载远程数据 "/>

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

商品编号 " dataField="shopId"/>

商品名称 " dataField="shopName"/>

商晶单价 " dataField="price"/>

商品类别 " dataField="catalog"/>

Ø 将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 getAllShop(){

//访问数据库代码

List shops = new ArrayList();

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。使用记事本打开该文件,在根节点中添加一个子节点。 

com.soft.flex.service.Service

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

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

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

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

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();

}

 

]]>

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

result="shopRemotingObject_resultHandler(event)"

fault="shopRemotingObject_faultHandler(event)">

示例">

加载远程数据 " click="btnLoad_clickHandler(event)"/>

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

商品编号 " dataField="shopId"/>

商品名称 " dataField="shopName"/>

商晶单价 " dataField="price"/>

商品类别 " dataField="catalog"/>

Ø 重新发布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中的基本类型)

3 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

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

java.lang.Byte, byte[]

int

如果 i 小于 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支持,并将以下 2 部分 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 应用的前端控制器处理所有应用请求)

 

  Spring MVC Dispatcher Servlet

  org.springframework.web.servlet.DispatcherServlet

  

    contextConfigLocation

    /WEB-INF/web-application-config.xml

  

  1

 

  Spring MVC Dispatcher Servlet

  /messagebroker/*

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

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

 

       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">

 

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

 

       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">

 

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

 

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

 

  

 

至此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

 

 

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

 

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

示例5.4

客户端代码:

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

   creationComplete="consumer.subscribe();"

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

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);

}

 

]]>

  

     

     

     

     

 

  

     

     

     

  发送消息" height="43" width="77" click="send()"/>   

    

    

 

 

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

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

 

    

        

       

    

 

   

  

          

           

              

                0   

               

               

               1000   

                0   

                false   

              

           

           

           

           

       

 

 

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

 

    

        

        

                

   

 

     

      

    

        

        

 

        

    

 

    

 

    

               

               

               0   

                50   

                5000   

                  

                       

                      

                   

              

        

        

            

        

 

        

            

            

                false

            

        

 

        

            

            

                true

                4

            

        

 

      

        

            

        

  

    

 

    

        

            

                [BlazeDS]

                false

                false

                false

                false

            

            

                Endpoint.*

                Service.*

                Configuration

            

        

    

 

    

        

            false

            

        

    

 

运行应用效果如图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 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="";

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

     CupService service = new CupService();

     //如果是查询所有

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

     List 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 += "";

        

        

         }

    

     }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 += "";

    

    

     }

    

    

    

    

    

     xml+="";

     //输出结尾标志

     out.print(xml);

out.flush();

out.close();

}

 

}

 

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

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

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

   initialize="application1_initializeHandler(event)"

   >

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();

}

 

]]>

使用HttpService 与后台通信" horizontalCenter="0" verticalCenter="0">

代号" dataField="countryId"/>

国家" dataField="countryName"/>

金牌数" dataField="goldMedal"/>

银牌数" dataField="silverMedal"/>

 

铜牌数" dataField="bronzeMedal"/>

 

选择国家:" height="23" verticalAlign="middle"/>

 

显示全部" click="application1_initializeHandler(event as FlexEvent)"/>

请选择国家" change="ddl_changeHandler(event)">

 

(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,配置业务类

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

 

    

        

    

 

    

        

    

com.soft.flex.flex4sj.service.CupService

 

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

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

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

   initialize="application1_initializeHandler(event)"

   >

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);

}

 

]]>

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

fault="myremoting_faultHandler(event)"

>

使用HttpService 与后台通信" horizontalCenter="0" verticalCenter="0">

代号" dataField="countryId"/>

国家" dataField="countryName"/>

金牌数" dataField="goldMedal"/>

银牌数" dataField="silverMedal"/>

 

铜牌数" dataField="bronzeMedal"/>

 

选择国家:" height="23" verticalAlign="middle"/>

 

显示全部" click="application1_initializeHandler(event as FlexEvent)"/>

请选择国家" change="ddl_changeHandler(event)">

 

 

运行应用,效果如图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 getAll(){

return dao.findAll();

}

public List 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中配置业务类。

       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">

         

  

  

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

sj43

 

flex.class.path

/WEB-INF/flex/hotfixes,/WEB-INF/flex/jars

 

flex.messaging.HttpFlexSession

 

  Spring MVC Dispatcher Servlet

  org.springframework.web.servlet.DispatcherServlet

  

    contextConfigLocation

    classpath:applicationContext.xml

  

  1

 

  Spring MVC Dispatcher Servlet

  /messagebroker/*

index.html

index.htm

index.jsp

default.html

default.htm

default.jsp

 

(7)修改MXML代码如下:

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

fault="myremoting_faultHandler(event)"

>

其中destination=serviceservice要与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文件 添加分页栏 。

   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="*">

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());

}

]]>

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

fault="myremoting_faultHandler(event)"

>

使用HttpService 与后台通信" horizontalCenter="0" verticalCenter="25">

代号" dataField="countryId"/>

国家" dataField="countryName"/>

金牌数" dataField="goldMedal"/>

银牌数" dataField="silverMedal"/>

铜牌数" dataField="bronzeMedal"/>

选择国家:" height="23" verticalAlign="middle"/>

显示全部" click="application1_initializeHandler(event as FlexEvent)"/>

请选择国家" change="ddl_changeHandler(event)">

'+pageData.currentPage+'/'+pageData.totalPage+''+' '+pageData.totalClum+'条记录'}"/>

首页"  click="loadData(1)"  enabled="{lbtnPrevious.enabled}" fontSize="12"/>

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

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

尾页" click="loadData(pageData.totalPage)" enabled="{lbtnNext.enabled}" fontSize="12"/>

每页显示:"/>

                                                                                                        

   

"/>

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

 

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,将获取到的结果显示在表格组件中。

你可能感兴趣的:(前端技术,道本自然)