视频课: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所开发的企业应用系统是异构的分布式系统,这种异构分布式系统给我们带来了以下需要思考的问题:
Ø 异构的客户端系统和服务器端系统如何通信?
Ø 如何保持分布式的客户端系统和服务器端系统之间的状态一致性?
我们在进行架构设计时,必须要清楚并解决这些问题,才能顺利进行企业应用开发,下面两个小节主要针对以上两个问题进行阐述,并给出解决方案。
开发异构系统时,如何进行通信和传递数据是我们比较关注的问题。使用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));"/>
这个例子的运行需要能够访问互联网,在本例中通过调用URL为http://weblogs.macromedia.com/mchotin/index.xml的HTTPService ,返回了一个XML文件,并将这个XML作为Datagrid控件的dataProvider,从而通过Datagrid将XML文件中的数据展示出来。XML中的数据主要是网站最近的发帖记录。这个例子说明,HTTPService的工作方式主要通过请求URL获取XML格式数据。
上例运行后 效果如图5.1.3所示。
图5.1.3 HttpService 示例
同HTTPService类似,Flex应用可以调用URL所表示WSDL 1.1服务,返回SOAP1.1格式的调用结果。SOAP也是基于XML格式规范,因此。使用HTTPService和WebService组件同服务器之间的交互都是通过XML进行的。下面是Adobe官方关于WebService组件的例子应用。
layout="absolute" creationComplete="wsBlogAggr.getMostPopularPosts.send()"> wsdl="http://weblogs.macromedia.com/mxna/webservices/ mxna2.cfc?wsdl" useProxy="false"> 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的博客。
通过这两个例子我们可以看到,使用HTTPService和WebService无需第三方框架,在服务器端直接编写相应的服务即可,所以比较容易理解和使用。但是,无论使用HTTPService还是WebService访问服务器,Flex客户端和服务器之间传递的都是XML数据,客户端和服务器端处理的也是XML数据。对于企业应用来说,客户端和服务器端交互的数据量往往很大,因此使用XML作为数据交换格式会降低传输效率和转换效率。同时,处理XML数据的代码也远比处理对象的代码繁琐,并且难以阅读和调试。因此,在企业应用开发中,客户端系统和服务器端系统之间采用HTTPService和WebService进行通信的部分较少,即使使用这两个组件。也应当用来传递少量、数据格式不易发生变化的数据。
在企业应用开发中,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。
BlazeDS是LCDS的开源版,只不过BlazeDS不具备LCDS的一些高级功能,比如:
Ø 高级客户端-服务器数据同步功能。
Ø 冲突检测/解决。
Ø Adobe AIR应用的离线数据管理服务。
Ø 由RIA生成PDF等。
使用BlazeDS与LCDS进行企业应用开发的配置完全一样,因此,在不需要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类似的功能,开发者可以根据实际情况加以选择,但是由于它们的原理相同,所以可以使用相同架构方法和设计模式。
本节的任务是创建一个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">
Ø 将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
//访问数据库代码
List
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。使用记事本打开该文件,在根节点中添加一个子节点。
在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)"> designViewDataType="flat" width="562" height="241" x="0" y="0">
Ø 重新发布remotingApp,再次运行remotingApp.mxml文件,单击“加载远程数据”按钮, Flex会调用远程Java类查询数据库的商品信息并显示出来,如图5.1.10所示。
图5.1.10
为了传输对象,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 Player将ActionScript对象编码成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 |
Boolean、boolean 和 String |
Flash.utils.ByteArray |
byte [] |
|
Flash.utils.IExternalizable |
java.io.Externalizable |
|
Date |
java.util.Date (已设置为协调世界时 (UTC) 格式) |
java.util.Date、java.util.Calendar、java.sql.Timestamp、java.sql.Time 和 java.sql.Date |
int/uint |
java.lang.Integer |
java.lang.Double、java.lang.Long、java.lang.Float、java.lang.Integer、java.lang.Short、java.lang.Byte、java.math.BigDecimal、java.math.BigInteger、String,以及基元类型 double、long、float、int、short 和 byte |
Null |
null |
基元 |
Number |
java.lang.Double |
java.lang.Double、java.lang.Long、java.lang.Float、java.lang.Integer、java.lang.Short、java.lang.Byte、java.math.BigDecimal、java.math.BigInteger、String、0(零) 如果发送了 null,则为基元类型 double、long、float、int、short 和 byte |
Object(泛型) |
java.util.Map |
如果指定了 Map 接口,则为 java.util.Map 创建一个新的 java.util.HashMap,为 java.util.SortedMap 创建一个新的 java.util.TreeMap。 |
String |
java.lang.String |
java.lang.String、java.lang.Boolean、java.lang.Number、java.math.BigInteger、java.math.BigDecimal、char[]、以及任何基元数字类型 |
有类型对象 |
有类型对象 在使用 [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元素。
对于ActionScript的String类型,由于可以匹配的Java的String类型,因此优先转换成字符串,但如果远程Java对象中没有方法的签名能够匹配,BlazeDS将尝试将字符串转换成Boolean(如果字符串是true,false)或数值类型(如果字符串表示一个数值)。
如果将ActionScript的null 或者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.3是DataRow对象在服务器端的定义,它与前端代码基本相似,唯一不同的是它有两个构造函数,默认构造函数用于反序列化(因为反序列化必须要有无参构造函数),:另一构造函数用于服务器端创建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。
如果需要BlazeDs与Spring框架整合使用,是非常简单的事情,因为,SpringSource和Adobe已经合作为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 特征
Ø MessageBroker(BlazeDS 的核心组件)被配置为 Spring 管理的 Bean
Ø Flex 客户端发出的 HTTP 消息通过 Spring 的 DispatcherServlet 路由给 MessageBroker
Ø Remote objects 以 Spring 的方式配置在 Spring 配置文件内
下面我们演示BlazeDS和Spring的整合。
(1)准备所需 jar 包
下载 Spring Framework dependencies和Spring 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 应用的前端控制器处理所有应用请求)
(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
至此BlazeDS与Spring的整合就完成了。
BlazeDS消息服务(Message Service )提供发布(publish)/订阅(subscribe)机制,允许 Flex 应用程序发布消息、订阅消息终端(messaging destination),从而实现实时数据的推动和协作传送。
(1)Message 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 频道是最好选择。
(2)IE 与 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请求通常只需要一个连接, 理论上我们可以最多可以建立7个HTTP streaming连接。
(3)messaging-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提供了 Producer和Consumer这两个组件,让你用来向目标地址发送或订阅消息。如果要订阅消息,你就使用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); } ]]>
服务器端services-config.xml定义Streaming通道:
class="flex.messaging.services.MessageService">
服务器端messaging-config.xm中定义目标并指定通道:
运行应用效果如图5.1.11所示,轻松实现了数据的推送:
图5.1.11 Flex数据推送
任务实训部分
训练技能点
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
//模拟数据库数据
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
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(); } ]]>
(6)运行应用程序,效果如图5.2.1所示。
图5.2.1 HttpService 示例
训练技能点
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">
(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)" >
运行应用,效果如图5.2.1所示。
训练技能点
Ø 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
return dao.findAll();
}
public List
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文件如下:
(7)修改MXML代码如下:
endpoint="http://localhost:8080/sj43/messagebroker/amf" fault="myremoting_faultHandler(event)" > 其中destination=“service” service要与applicationContext.xml中业务bean的id一致。 运行应用程序,效果如图5.2.1.所示(注意要在服务器中将重复的cglib.jar删去)。 训练技能点 Ø 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视图 开发与Java端Page类对应的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)" > (6)运行应用程序,效果如图5.2.4所示。 图5.2.4 分页 巩固练习 选择题 1. Flex与外部进行数据通信的方式有() A. HTTPService。 B. WebService。 C. Remoting。 D. HttpRequest。 2. 以下关于Flex中Remoting数据通信方式的说法,正确的是() 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数据库中的商品信息表,并返回结果。然后通过Flex的WebService组件调用webservice,将获取到的结果显示在表格组件中。实训任务4:实现分页