翻译旧文:用Adobe Flex 2和Java创建富Internet应用

注:本文是2006年翻译,技术已经过时了。

 

用Adobe Flex 2和Java创建富Internet应用 
Flash + POJO = RIAs 
Victor Rasputnis,Yakov Fain,Anatole Tartakovsky 

一般的Java开发者知道,当需要为Java应用程序开发GUI时,Swing是一个工具。Eclipse SWT也有很多拥护者,但多数人使用Swing。十年来,经验证明Swing开发GUI并不轻松,你必须精通事件派发线程,GridBagLayout等等。近来,NetBean团队创建了一个叫作Matisse的不错的GUI设计工具,并且它已经集成到MyEclipse开发环境。和Matisse相比而言,JBuilder是最棒Swing GUI工具,但它太贵了。目前,优秀的GUI设计者使用免费的NetBean。 
为什么不考虑使用Flex开发富Internet应用(Rich Internet Applications,简称RIA)? 首先,我们给出一个简短的回答。看一下Listing 1示例代码。这段代码编译并运行在Flash播放器中,运行结果如Figure 1所示。对,它是一个拥有几个节点的树控件,它能展开、收缩,还能突出显示用户选中的节点。想象一下实现相同功能要编写多少Java代码。 

Listing 1: HelloTree.mxml 

<?xml version="1.0" encoding="utf-8"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" layout="vertical"> 

<mx:Label text="Rich Internet Applications with Adobe Flex and Java"/> 
<mx:Tree id="tree1" labelField="@label" showRoot="false" width="400"> 
        <mx:dataProvider> 
            <mx:XML format="e4x"> 
                <folder label="TOC"> 
                 <folder label="Chapter 1"/> 
                 <folder label="Chapter 2"/> 
                 <folder label="Chapter 3" > 
                    <Sample label="HelloWorld" /> 
                    <Sample label="HelloBasil" /> 
                    <Sample label="HelloBasilAS" /> 
                    <Sample label="HelloTree" /> 
                 </folder> 
                 <folder label="Chapter 4" /> 
                </folder> 
            </mx:XML> 
        </mx:dataProvider> 
</mx:Tree> 
</mx:Application> 

 

这段代码优雅而简洁;界面也显得漂亮迷人。Flex编译器自动地将Listing 1中的MXML代码转换成OO语言ActionScript(译注:符合ECMAScript规范,与JacaScript类似),然后再将它编译并生成一个可被Flash播放器识别、运行的SWF文件。 

要给这个示例添加商业逻辑处理,我们需要用ActionScript 3.0语言编写事件处理过程,这与Java有些类似,但我们不必担心路由所有事件到事件派发队列等麻烦。Flex/Flash相结合进行RIA开发是一种很有前途的技术,下面列举一些原因: 
• Flash播放器是一个强大的跨平台的、拥有一个高性能的byte code/JIT编译器以及丰富UI API的虚拟机。 
• 虚拟机(译注:即ActionScript Virtual Machine,简称AVM)体积很小。 
• 易与Web浏览器集成。 
• Flash应用可以在Web浏览器之外运行(指不使用Web浏览器也可以运行)。 
• Flex提供了基于组件的编程方式,消除了大部分低级别的编码。 
• 它提供了与多种媒体(例如视频和声音)的简单整合。Java Swing在这方面很落后。 
• 与Adobe其他产品类似,它有快速的采用率(指易于被接受使用)。 
• 最重要的是,Flex 2很容易在服务端与Java进行集成。 
我们稍后用Flex开发一个Stock Portfolio应用程序,再把它与POJOs集成。 
Flex客户端应用程序编译成SWF文件并传递到客户端,在Flash播放器(作为插件安装到Web浏览器)运行。Flex客户端由Flash播放器、预置组件框架、几个编译器以及一个基于Eclipse插件的Flex Builder IDE组成。Flex服务器端是一个Web应用程序(译注:详见Flex的部署部分),由Flex Data Services(FDS)和Flex图形组件组成,它们能部署在任意的J2EE服务器中。 

要了解Flex实战应用,让我们编写功能实现,然后开发并部署一个示例应用。 

设计Stock Portfolio应用程序 
我们要创建一个Web应用程序,它接收并显示股票价格及最近新闻(如图2、3所示)。 
顶部界面(译注:即主界面的TOP部分)必须放置用户投资的各种股票。为简单起见。在XML文件存储用户投资信息(见Listing 2)。 
Listing 2: portfolio.xml 片段 

<portfolio> 
      <security> 
            <Symbol>MSFT</Symbol> 
            <Quantity>10000</Quantity> 
            <Price>20.56</Price> 
            <Value>1</Value> 
       </security> 
       <security> 
           <Symbol>IBM</Symbol> 
           <Quantity>3000</Quantity> 
           <Price>80.21</Price> 
           <Value>1</Value> 
       </security> 
    ... 
</portfolio> 

当用户点击一行具体股票(例如,Figure 2显示的ADBE),在一个带表头的数据表格中更新该股票。新闻来自http://finance.yahoo.com/rss/headline。有一列存放关联新闻的URLs,当用户点击该链接,打开一个新的Web浏览器界面并显示该新闻。 
 
顶部界面应包含一个toggle按钮Show Grid/Show Chart。当Show Grid选项选中,用户将看到类似Figure 2的画面;当Show Chart选项选中,之前的数据表格被一个饼状图代替(见Figure 3),该图功能不变(点击饼状图的某块会弹出新闻标题)。(股票)市场数据大概每秒钟刷新一次。 
  

受文章大小限制,我们在服务器端仅编写一个简单的POJO对象,它能产生一个随机数并将其推送到Flash客户端。不过,在后续文章我们会添加通过JMS从外部Java应用程序掘取数据的功能。 
对于一个短小的杂志文章,这听起来这是一个野心勃勃的任务,不是吗?本文不是Flex MXML或ActionScript的指南,但作为一个Java开发者,你应该能明白如何以尽可能少的解释把代码组织在一起。在部署运行本示例后你能更加正式地学习Flex。那么,卷起袖子,让我们开始吧… 

安装Flex Builder 和 Flex Data Services 
本文写作时,Flex 2 仍然处于beta版,正式产品发布预计在夏季(译注:作者指的是2006年夏季,目前你可以从Adobe免费得到试用版)。问题出现了,“它是免费的吗?”。答案是,看情况。它是一顿“免费午餐”(更像是厨师免费赠送的饭前开胃品),但这只会增进你的食欲,随后你的手会慢慢伸向钱包。Flex Data Services (FDS)提供了Flex与企业级数据和消息应用(已投资部署)的无缝集成。对于一个支持客户端认证机制、面向消息的等特性的高性能企业级应用,你可能会购买FDS协议。对于小型应用,你可以通过HTTPService、Web Services、使用标准或开源技术的Remote Java Invocation(与已有系统)集成。 

免费部分包括Flex命令行编译器和包含所有富组件库的Flex Framawork。这意味着你可以使用任意一种简单的字编辑器来编写Flex代码,编译成SWF文件,在免费Flash播放器9中运行。可是到目前为止,Adobe宣称基于Eclipse的Flex Builder IDE使得开发更有效率,但它不是免费的。Flex 图形组件提供客户端丰富的交互能力,同样也不是免费的。 
Flex Builder IDE 有两种形式:标准版和Eclipse插件版。在安装过程你将会选择其中一种方式。让我们首先从www.eclipse.org/downloads/下载 (除非你已经准备妥当)安装Eclipse 3.1,然后安装插件版的Flex Builder。在安装过程,你必须指定Eclipse所在目录(拥有plug-ins子目录的那个)。安装完毕,启动Eclipse,选中菜单 Window | Open perspective | Other 并添加Flex Development perspective(Flex Debugging perspective将会自动添加)。Flex Builder带有大量帮助,插件版它隐藏于菜单Help | Help Contents | Adobe Help。 

仅运行客户端Flex 应用,我们需安装另一个程序:Flash播放器9。可是,对于我们的stock portfolio应用程序,我们还需安装部署FDS(译注:详见Flex相关帮助)。FDS实际上一个部署在兼容J2EE容器的Web应用程序。既然Flex是一个Web应用程序,你可以把它部署到你选择的应用服务器中。首先,我们从http://tomcat.apache.org/下载安装Apache Tomcat 5.5。默认情况下,在Windows机器上Tomcat 安装在"C:\Program Files\Apache Software Foundation\Tomcat 5.5"路径下,运行在8080端口。安装完成后,Apache Tomcat Server将会作为一个Windows服务启动。现在,下载并执行FDS安装程序(默认安装目录是C:\fds2),选中Flex Data Services J2EE应用程序选项。安装结束后,解压缩flex.war并拷贝至Tomcat的webapps\ROOT下并重新启动Tomcat服务。在你的Web浏览器中输入URL http://127.0.0.1:8080/ 后你会看到FDS欢迎画面。至此,Flex Data Services 已经部署到Tomcat下。 

用Flex开发Stock Portfolio 应用程序 
什么在运行?运行在哪里? 
首先,让我们看一下哪些组件将会在客户端运行,哪些组件属于Web服务器。Listing 3-6展示的代码将编译成portfolio.swf ,它运行在客户端,不管是独立地运行在Flash 播放器8.5中,还是运行在已安装Flash插件的Web浏览器中的portfolio.html (由Flex Builder自动生成)。Tomcat是我们的服务器,它将作为已编译的Java类(Listing 7、8)文件的宿主。我们还需要在服务器端处理一些附加的配置文件(见Listing 9、10)以指定从哪查找这些Java类文件及接收对外部Yahoo!Service访问的返回结果。同时,Flex提供了不同的client/server 通讯方式(RemoteObjects, HTTPService, WebService),本文中我们的客户端将通过<mx:RemoteObject>使用RPC组件来查找和匹配已配置的位于服务器的Java类文件(正如本文末尾描述的一样)。 

开发GUI部分 
在Eclipse中打开Flex perspective 并创建一个包含Listing 3-7文件的新项目(例如, Portfolio_RCP),然后会编译并生成一个叫做portfolio.swf的文件. 为部署方便,把该项目的output directory 设置为 Tomcat的 \ROOT\portfolio. 
主文件portfolio.mxml (见 Listing 3) 将屏幕设为一个(在部分区域间)带有可调整分割条的垂直Box(<mx:VDividedBox>)类型的布局器(想象一下Swing的分割面板), 它有两个分离的代码段组成。底部子容器(译注:UI容器)包含一个数据表格,代码在<FinancialNews> (见Listing 6)。顶部子容器包含一个 <PortfolioView> (见Listing 4)。 
Listing 3: Portfolio.mxml 

<?xml version="1.0" encoding="utf-8"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
xmlns="*" layout="vertical"> 
<mx:VDividedBox width="100%" height="100%"> 
    <PortfolioView id="pv"/> 
  <FinancialNews id="fn"  security="{pv.selectedSecurity}"/> 
</mx:VDividedBox> 
</mx:Application> 


Listing 4: 顶部面板内容: PortfolioView.mxml 

<?xml version="1.0" encoding="utf-8"?> 
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*"  
    width="100%" height="100%"  creationComplete="startQuotes();"    > 
<mx:XML  format="e4x" id="portfolioModel" source="portfolio.xml" /> 
<mx:Panel width="100%" height="100%" title="Portfolio"> 
<mx:ViewStack id="vs" width="100%" height="100%"> 
<mx:VBox label="Show Grid"  icon="iconGrid" > 
<mx:DataGrid id="portfolioGrid" width="100%" height="100%" 
        dataProvider="{portfolioModel.security}" 
change="selectedSecurity = portfolioGrid.selectedItem.Symbol;"> 
<mx:columns><mx:Array> 
<mx:DataGridColumn dataField="Symbol"/> 
<mx:DataGridColumn dataField="Quantity" textAlign="right"/> 
<mx:DataGridColumn dataField="Price" textAlign="right"/> 
<mx:DataGridColumn dataField="Value" textAlign="right"/> 
</mx:Array></mx:columns> 
</mx:DataGrid> 

</mx:VBox> 
<mx:HBox label="Show Chart"  icon="iconChart"   horizontalAlign="center" 
verticalAlign="middle"> 
<mx:PieChart id="portfolioPie" dataProvider="{portfolioModel.security}" showDataTips="true" 
itemClick="selectedSecurity=event.hitData.item.Symbol"  height="90%"> 
<mx:series> 
            <mx:Array> 
            <mx:PieSeries labelPosition="callout" field="Value"   labelFunction="showPosition" nameField="Symbol" 
explodeRadius="2"/></mx:Array> 
             </mx:series> 
</mx:PieChart> 
<mx:Legend  verticalAlign="middle" dataProvider="{portfolioPie}" label="{data.Symbol}"/> 
</mx:HBox> 
</mx:ViewStack> 
</mx:Panel> 
<mx:HBox horizontalAlign="right"  width="98%" > 
    <mx:ToggleButtonBar   dataProvider="{vs}" paddingTop="4" /> 
</mx:HBox> 
<mx:RemoteObject  destination="Portfolio" id="freshQuotes"  > 
      <mx:method name="getQuotes" concurrency="last"      result="applyQuotes(event.result as Array)"/> 
</mx:RemoteObject> 
<!-- mx:Consumer id="consumer" destination="chat-topic-jms" 
message="applyQuotes(event.message.body.quotes)"    / --> 

   <mx:Script><![CDATA[ 
        import mx.controls.Alert; 
        [Bindable] public var selectedSecurity:String; 
         private function showPosition(data:Object, field:String, index:Number, percentValue:Number):String { 
            return data.Symbol +  "\n" + "Shares:" + data.Quantity + "\n" + "Price:" + data.Price + "\n" + 
"Value:" + data.Value ; 
        } 
        [Embed(source="images/icon_chart.png")] public var iconChart : Class; 
        [Embed(source="images/icon_grid.png")]  public var iconGrid : Class; 

        import com.theriabook.jms.dto.StockQuoteDTO; 
        private function applyQuotes(quotes: Array):void { 
            for (var i:int=0; i<quotes.length; i++) { 
quote = StockQuoteDTO(quotes[i]);  //casting 
var row:* = ortfolioModel.security.(Symbol==quote.symbol); 
row.Price = Math.round(100*quote.last)/100; 
row.Value = Math.round(row.Price * row.Quantity); 
            } 
        } 
internal var quote:StockQuoteDTO = null; 
private function startQuotes():void{ 
setInterval(function ()  { freshQuotes.getQuotes(); }, 1000); 
//consumer.subscribe(); 

    ]]></mx:Script> 
</mx:Canvas> 

Listing 6: 底部面板内容: FinancialNews.mxml 

<?xml version="1.0" encoding="utf-8"?> 
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" width="100%" height="100%"> 
<mx:DataGrid id="newsGrid" width="100%" height="100%" 
dataProvider="{newsList}"  variableRowHeight="true"> 
<mx:columns> 
<mx:Array> 
<mx:DataGridColumn headerText="Date" dataField="pubDate" width="200"/> 
<mx:DataGridColumn headerText="Title" dataField="title"   wordWrap="true" /> 
<mx:DataGridColumn headerText="Description" dataField="description"  wordWrap="true"   /> 
<mx:DataGridColumn headerText="Link" width="130"> 
<mx:itemRenderer> 
  <mx:Component> 
          <mx:LinkButton label="{data.link}" 

          click="navigateToURL(new URLRequest(data.link), '_blank')"/> 
  </mx:Component> 
</mx:itemRenderer> 
</mx:DataGridColumn> 
</mx:Array> 
</mx:columns> 
</mx:DataGrid> 

<mx:XMLListCollection id="newsList" source="{newsFeed.result.channel.item}" /> 
<mx:HTTPService id="newsFeed"  useProxy="true" 
destination="YahooFinancialNews"   concurrency="last" 
resultFormat="e4x" > 
</mx:HTTPService> 
<mx:Script> 
<![CDATA[ 
public function set security(value: String):void { 
newsFeed.send({s:value}); 

]]> 
</mx:Script> 
</mx:Canvas> 

Java 开发者知道,一些Swing组件将GUI部分和数据部分分离,例如JTable从数据模型类获取数据,而这些数据存储在一个Java容器(译注:对象容器)。与此类似,一些 Flex 控件(例如, <mx:DataGrid>)也可以使用ActionScript collection 类作为数据供给者。我们的数据模型就是portfolio.xml文件(在Listing 2描述)。 
这段代码表现了一个典型的主-从关系,当改变主控件<PortfolioView> 中的选择的股票,更新与之相联系的<FinancialNews>组件内容。

获取价格 
让我们聚焦一些编写顶部面板采取的值得关注的编程技巧。这个顶部面板容纳了许多Flex框架组件,它们被包装到一个Canvas容器里(见Listing 4)。了解完这部分,用户投资将被portfolio.xml 展现,你可能期望至少有几行演示的XML被处理。 
你对下面这行代码有何看法: 
<mx:XML format="e4x" id="portfolioModel" source="portfolio.xml" /> 
XML处理完毕!在此行代码之后你可以采用简单的点符号操作(例如,portfolioModel.security)遍历整个XML文档。魔法管用是由于Flex支持W3C引入的作为读取和处理XML文档的e4x格式。 

另一个要提到的值得关注的特性是数据绑定,这是一种连接某个对象数据到另一对象的途径。尤其,这是一种在GUI和非显示性组件之间传递数据的简便途径。数据绑定可通过使用闭合花括号语法指定。下面几行代码来自Listing 4,它为顶部数据表格和图表提供了当数据供给者一发生变化就直接刷新的机制。 

<mx:DataGrid id="portfolioGrid" width="100%" height="100%" 
      dataProvider="{portfolioModel.security}" 
<mx:PieChart id="portfolioPie" dataProvider="{portfolioModel.security}" 

变量portfolioModel.security 表示数据源, 当源的任意属性变化时,目的立即变化。注意,我们把一个数据源与两个目的映射 (数据表格和饼状图), 因此我们在市场数据改变股票属性时,不需做任何附加编码就能刷新数据表格和图形。 
标记<mx:RemoteObject destination="Portfolio" id="freshQuotes" > 声明了客户端到一个位于服务器端的被称为"Portfolio"(见Listing 10)远程对象的连接。 
Listing 10: 配置Flex远程服务 

<destination id="Portfolio"> 
        <properties> 
            <source>com.theriabook.ro.Portfolio</source> 
        </properties> 
</destination> 
Listing 4 在mxml文件的<mx:Script>标记里嵌入ActionScript代码。它是一个公有的以[Bindable]元数据语法标记的变量: 
[Bindable] public var selectedSecurity:String; 

该变量将会在值改变时自动地向所有注册的侦听者发送通知。它将在数据表格改变事件或用户点击饼状图的某块时发生。选择一个不同的股票符号(证券)将触发新闻表格的重绘。不需任何编码即可完成。稍等,我们没有为变量selectedSecurity 编写任何事件侦听过程!没错,但当Flex编译Portfolio.mxml(见Listing 3)时,它将注意到这个绑定的公有变量pv.selectedSecurity,它不仅生成一个注册需要的侦听器,而且调用在FinancialNews面板的函数setsecurity (见Listing 6)。 

当顶级界面(<mx:Canvas>)描绘一完毕,显示结果马上开始。creationComplete 事件处理过程调用ActionScript函数startQuotes(),它将连接远程POJO并每隔1秒调用方法 getQuotes()。标记<mx:RemoteObject> 还包含一个元素以声明方法getQuotes()如何被调用。当该方法调用结果返回时,传递到函数applyQuotes()。所有远程调用都是异步的,需要在一个ActionScript方法中处理调用结果。我们的示例中,applyQuotes() 就是这么一个方法。属性concurrency 定义了远程对象如何处理多次请求。例如,用户请求某个股票的价格,但是没过多久,她又请求另一支股票的价格。属性concurrency="last" 表示旧的响应应该忽略掉。 

另一处值得注意的代码是Listing 4,有关ActionScript 语言e4x 对象访问能力的示例: 
var row:* = portfolioModel.security.(Symbol==quote.symbol); 
Flex 是一个对任何XML相关处理的优秀平台。它自动的在幕后把Symbol==quote.symbol 当作XPath 表达式处理,因此提供了无需编码的数据导航能力。 
和你卖个关子,我们决定保留代码中的注释行<mx:Consumer> 和consumer.subscribe(),并给你一个参考 — 在替换为AJAX风格的价格主动(它通过setInterval()完成价格轮询,而服务器采用publish/subscribe消息机制实现立即推送消息)更新机制时,会增加哪些代码。我们将在后续文章中介绍这个问题。 

顶部toggle 按钮Show Grid/Show Chart (见Figure 2)使用图像,这是一种在SWF文件中嵌入资源的好方法。浏览器在HTTP请求可以下载整个客户端 (但SWF文件大小会变大)。由于这些原因,人们将多个Java applet文件打成一个JAR包。 在Listing 4有两行代码,它们通过引用变量嵌入图像资源。 PorfolioView 显示它们如下: 
<mx:VBox label="Show Grid" icon="iconGrid" ...> 
      <mx:HBox label="Show Chart" icon="iconChart" ...> 

Listing 5包含的ActionScript代码用于客户端,它有助于Flex完成帮助Java反省如何更有效率;我们声明了一个拥有所有属性的ActionScript类,它等同于服务器端Java类 (见Listing8 )。 

Listing 5: 客户端 ActionScript 类:  StockQuoteDTO.as 

package com.theriabook.jms.dto  { 

[Managed] 
[RemoteClass(alias="com.theriabook.jms.dto.StockQuoteDTO")] 
public dynamic class StockQuoteDTO 

public var symbol:String; 
public var last:Number; 


Listing 8: 一个简单的股票价格生成器: Portfolio.java 

package com.theriabook.ro; 
import java.util.Random; 
import com.theriabook.jms.dto.StockQuoteDTO; 

public class Portfolio { 
static Random random = new Random(); 
static StockQuoteDTO[] quotes = { 
new StockQuoteDTO("IBM", 82.0), 
new StockQuoteDTO("MSFT", 27.0), 
new StockQuoteDTO("ADBE", 38.0), 
new StockQuoteDTO("ORCL", 13.0)}; 
double volatility=.05; 
public  StockQuoteDTO[] getQuotes() { 
for (int i = 0; i < quotes.length;i++){ 
quotes[i].last +=   random.nextGaussian()* volatility; 

    return quotes; 



获取财经新闻 
底部数据表格 (见Listing 6) 显示Web网址提供的新闻标题。此刻我们不再使用<mx:RemoteObject>,而是另一种叫做<mx:HTTPService> 的RPC调用方式指向http://finance.yahoo.com/rss/headline, 它是一个客户熟悉的类似YahooFinancialNews(见Listing 9)的URL。此外,HTTPService调用以异步方式工作,只要security setter 被调用(setsecurity),它将向服务器发生请求newsFeed.send({s:value})。本行里,"s"是一个参数名称,而其值应该包含一只选中的股票名称。例如,如果用户选择MSFT,服务器目的地YahooFinancialNews 将会收到一个URL:http://finance.yahoo.com/rss/headline?s=MSFT。试着在你的Web浏览器手工输入这个URL,我们Flash客户端会收到调用结果并看到XML。 
收到的XML用作<mx:XMLListCollection>的源(source)属性。数据表格的列已经和源数据提供者XML文档的节点映射。当调用结果(newsFeed的属性之一)达到时,容器和GUI会刷新它。你不必使用一个容器当作数据和GUI之间的协调者。不过,容器使用便捷,如果你愿意在展示数据给用户之前做一些特殊处理,例如使用e4x过滤或搜索。 

下列一行代码把HTTPService请求的返回结果存入一个XMLListCollection的source属性: 
<mx:XMLListCollection id="newsList" source="{newsFeed.result.channel.item}" /> 
如果你再次观察URL http://finance.yahoo.com/rss/headline?s=MSFT返回的XML结果的结构,你会注意到途径(译注:此处指的是获取新闻标题)是一个叫做item的元素它表示一个新闻标题。 

(数据表格)A组合元素最后一列是一个叫做<mx:LinkButton>的组件。它是一个看似超链接的按钮。我们小心的把它包裹到一个<mx:Component>容器中。该容器依次位于<mx:ItemRenderer>(想象一个Swing单元格渲染器)。单击该链接导向到一个URL并打开一个弹出窗口。URLRequst构造器参数是一个data.link;数据是当前行数据的引用,链接是列名。 
现在,在Eclipse环境打开Java perspective 并创建一个新项目(例如, Portfolio_RCP_RO), 它将包含我们的Java类。生存于Tomcat服务器的POJOs 非常简单。StockQuoteDTO .java (见Listing 7) 包含一只选定股票的最新价格。Portfolio.java (见Listing 类很简单,随机数产生器模拟几只指定编码的股票实时市场环境价格变化情况。已编译的Java 类应该部署到 Tomcat的目录 WEB-INF\classes下面。 
Listing 7: The Java counterpart: StockQuoteDTO.java 

package com.theriabook.jms.dto; 
import java.io.Serializable; 
public class StockQuoteDTO implements Serializable { 
private static final long serialVersionUID = 4672447577075475117L; 
public String symbol; 
public double last; 
public StockQuoteDTO(String sym, double newPrice){ 
symbol = sym; 
last = newPrice; 



Listing 9: 配置代理以允许访问外部服务器 

<destination id="YahooFinancialNews"> 
        <properties> 
            <url>http://finance.yahoo.com/rss/headline</url> 
        </properties> 
</destination> 

配置服务器端的目的和代理 
基于安全考虑,Flash客户端仅能访问同一域内的服务器,除非有一个服务器和外部服务提供者之间的协议,它允许(客户端)处理服务器和crossdomain.xml 声明的(外部服务提供者)。然而,我们的portfolio SWF文件并不是位于finance.yahoo.com, 并且我们没有被允许在Yahoo! Servers 安装crossdomain.xml。我们将使用另一个叫做Flex 代理的技巧。当用户在数据表格点击新闻链接时,portfolio 客户端将连接我们的部署在Tomcat的FDS 应用程序, 它将代理我们与Yahoo!的通讯。要配置Flex 代理服务,见位于Tomcat 的\WEB-INF\flex 目录的flex-proxy-service.xml文件下列部分 (见Listing 9)。 
现在,FDS 将联系http://finance.yahoo.com, 获取指定代码的新闻,并将它返回Flash客户端。 
至于服务器端的POJO,Flex提供了配置文件通过指定叫做目的方法允许你隐藏实际的服务提供者的细节(例如,它的真实名称)。写列部分来自Listing 10,它被加入flex-remoting-service.xml 文件。 
客户端不知道,我们的POJO实际名称就是com.theriabook.ro.Portfolio, 但他们通过昵称Portfolio引用它。 
现在,启动你的Tomcat服务并在Flex Builder项目Portfolio_RCP运行Flex 应用 (portfolio.mxml)。你应在屏幕看到类似Figure 2、Figure 3的结果,"market data feed" 可更改价格,之后你会在最近Yahoo新闻读到关于你的股票的最新价格。 

结论 
在本文,我们设法开发一个有价值的应用,但我们编写的代码很少。不幸的是,我们能提供的讲解同样也很少。如果你愿意学习Flex 2,你可以在http://labs.macromedia.com/wiki/index.php/Main_Page 找到高质量的入门资料和产品文档。我们即将要面世的书Rich Internet Applications with Adobe Flex and Java (www.theriabook.com ) 会向你展示如何使用高级和不常见Flex技巧来改造企业级Java应用程序。 

附 
本文源代码在Flex官方发布新版本后有改动。示例应用部署在Farata Systems 网站。URL (需要beta 版Flash 9 player): 
http://samples.faratasystems.com/porfolio/PortfolioRpcDemo.html 

源代码http://samples.faratasystems.com/porfolio/srcview/porfolio.zip 
请注意,自Flex Beta beta 3起,Flex Data Services' XML 配置文件改名了。 


关于 Victor Rasputnis 
Victor Rasputnis博士是Farata Systems的主要管理层负责人。他负责提供架构设计、实现管理和知道公司迁移到XML Internet技术。他拥有莫斯科自动化学院计算机系的博士学位。你可以通过电子邮件vrasputnis@faratasystems.com与他联系。 

关于 Yakov Fain 
Yakov Fain是Farata Systems的主要管理层负责人。他是许多Java书籍和许多技术文章的作者。今年秋天,SYS-CON Books 将出版他最近的书籍,"Rich Internet Applications with Adobe Flex and Java: Secrets of the Masters"。Sun Microsystems 提名并授予Yakov Java Champion名衔。他领导Princeton Java 用户组。Yakov在纽约大学教授Java 和Flex 2。他还是Adobe 认证的Flex 讲师。 

关于 Anatole Tartakovsky 
Anatole Tartakovsky 是Farata Systems的主要管理层负责人。他负责创建一些框架及可重用组件。Anatole 创作了关于AJAX、XML、Internet和client-server技术的很多书籍和文章. 他拥有数学硕士学位. 你可以通过电子邮件atartakovsky@faratasystems.com与他联系。

posted on 2014-06-10 22:31  draken  阅读(159)  评论(0编辑  收藏  举报

导航