视频课: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>

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

<?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的博客。

通过这两个例子我们可以看到,使用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对象的使用:

<?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。

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类似的功能,开发者可以根据实际情况加以选择,但是由于它们的原理相同,所以可以使用相同架构方法和设计模式。

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

1.4 BlazeDS和Spring整合

如果需要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 应用的前端控制器处理所有应用请求)

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

至此BlazeDS与Spring的整合就完成了。

1.5 BlazeDS的消息服务

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:

<default-channels>

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

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

</default-channels>

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

在客户端,Flex提供了 Producer和Consumer这两个组件,让你用来向目标地址发送或订阅消息。如果要订阅消息,你就使用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所示。

实训任务3:RemotingObject 整合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中业务bean的id一致。

运行应用程序,效果如图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视图 开发与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文件 添加分页栏 。

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

Flex与外部的数据通信相关推荐

  1. 用ExternalInterface实现Flex与外部容器交互

    有时候Flex需要与外部容器交互,比如和别的项目交互,调用外部数据,则可以通过ExternalInterface来实现.毕竟Flex版本还是比较"年轻",有些地方还不完美,需要借助 ...

  2. flex 读取外部txt文件时候出现中文乱码现象

    首先,flash读取txt出现乱码涉及到System.useCodepage这个静态属性属性 官方描述:"A Boolean value  that tells Flash Player w ...

  3. Flash/Flex与外部对象或数据交互的几种方式

    1.首先当然是发布的swf和浏览器容器直接的通信,有三种方式  1)使用flashvar直接传参数给swf,这是早期swf最主要的方式,也是美工们喜欢的  2)通过url 使用BrowserManag ...

  4. flex加载外部swf文件[flex-swf and flash as3 swf],并且互相通讯-加强原来的帖

    第一步:建立加载类[CtmObjLoader],此类可以加载文件类型 [图片文件或swf文件] package { import flash.display.DisplayObject;  impor ...

  5. FLEX里的CSS样式设置教材

    FLEX3中应用 CSS完全详解手册! 编辑完这个FLEX下的CSS说明后,我基本已经兵临崩溃边缘了.在些天在AIRIA下了不少好东西,今天终于有空,也发一个比较不错的东西给大家,相信 都比较需要这个 ...

  6. Flex css 运用

    申明:本文不是由我所写,是原作者 digman 发布在AIRIA论坛上面.转载自此方便自己查看.若作者不允许转载,请联系我.我会及时删除. FLEX3中应用CSS完全详解手册! 原文地址:http:/ ...

  7. HTML部分知识点整理

    一,主流浏览器的内核分别是什么? IE:trident;   1997年的ie4首次被采用沿用至今,腾讯,猎豹,360等浏览器都是用ie的内核.因其稳定性,目前国内银行政府等办公主要还是ie浏览器为主 ...

  8. 重新定义未来的汽车芯片角色 拼算力只是第一步

    汽车芯片赛道,正在经历"三年河东.三年河西"的变化. 随着L2级辅助驾驶增速加快,L2+甚至是L3成为上游芯片厂商争夺的下一个赛道.同时,整车电子架构的革新,整车OTA也驱动车企在 ...

  9. 前端小白如何学习 CSS

    很多人想让我给他们推荐有关CSS部分的教程,或者问我如何学习CSS. 我也看到很多人对CSS的部分内容感到困惑,一部分原因是由于对语言的过时认识. 鉴于CSS在过去几年中发生了相当大的变化,这是一个更 ...

最新文章

  1. qt与python互联_PYQT5 vscode联合操作qtdesigner的方法
  2. ROS教程(3)---静态NAT配置及应用 (
  3. Mac下修改环境变量
  4. webservice的css哪里添加,jQuery_XML+XSLT+CSS+JQuery+WebService组建Asp.Net网(2), 3.       更 - phpStudy...
  5. git学习资料整理(知乎搜集的)
  6. Min_25 筛小结
  7. 大数据之Hive教程
  8. matlab销量预测的数学模型,数学建模:酒店最优化问题.用matlab算出《酒店价格预测模型》...
  9. PHP如何在微信中聊天_迷你微信私有聊天系统PHP源码支持PC、移动APP
  10. 《精通Spring MVC 4》——1.3 start.Spring.io简介
  11. Leetcode 214.最短回文串
  12. 光伏组件为何出现白色线条?
  13. MathType快捷键
  14. 字母消消乐游戏(C语言版本_2023首篇新作)
  15. Java - 什么是ORM?
  16. C++ 单词转换例子
  17. 有哪些好用的微信群管理工具?
  18. 【MM32F5270开发板试用】六、如何用 星辰内核 + 国产RTOS 通过I2S播放 “星辰大海”
  19. audioread-支持多种解码 (GStreamer + Core Audio + MAD + FFmpeg) 的python音频解码库
  20. pre 图像稳定_什么是图像稳定,它如何工作?

热门文章

  1. java中wait和sleep的区别
  2. 浅谈RDMA流控设计
  3. 关于Storm Tick
  4. springMVC 的工作原理和机制
  5. Gradle学习目录
  6. me)不支持html,属于me的vue练习(参考菜鸟教程).html
  7. java 实现 tcp_java实现TCP通信
  8. php投票系统制作,php简单的投票系统[原创]
  9. MiniGUI编程之Helloworld(一)
  10. html正则表达式的书写,前端正则表达式书写及常用的方法