Flex 之于 Java,就像美丽之于大脑,或者还有别的说法?谁能告诉我?我所知道的是,Flex 和 Java 真的是能配合得很好,能创建出难以置信的富 Internet 应用(RIA)。你会问 Flex 是什么?Flex 是一个开源框架,你可以通过基于标签的 MXML 语言(以及 ActionScript 3)来构建 Flash 应用。
请观看: Jack 有关 Flex 与 JSON 及 XML 互操作的演讲 (QuickTime 格式,33MB)。
你可以从 Adobe 的站点下载( http://adobe.com/flex )Flex IDE 即所谓 Flex Builder,并由此开始你的开发之旅。Flex Builder 是个商业产品,但它有很长的免费试用阶段,能让你有足够时间想清楚是不是值得掏这个钱。在这篇文章中,我会演示如何一起使用 Flex 和 Java。Java 会运行在服务器端,而 Flex 运行在客户端。这两端间的通信协议可以是任何你想要的协议。但在这里,我会先使用 XML,然后再使用 JSON,因为这两种技术是我们在 Web 2.0 的世界里最常见的。
创建服务器代码
XML 示例由列表 1 中显示的简单 JSP 文件开始:
<span color="#008000"><b> 列表 1. xml.jsp</b><br></br> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="1.2"><br></br> <jsp:directive.page import="java.text.*"/><br></br> <jsp:directive.page import="java.lang.*"/><br></br> <jsp:directive.page contentType="text/xml"/><br></br> <days><jsp:scriptlet><br></br> <![CDATA[<br></br> double compa = 1000.0;<br></br> double compb = 900.0;<br></br> for (int i = 0; i<=30; i++) {<br></br> compa += ( Math.random() * 100 ) - 50;<br></br> compb += ( Math.random() * 100 ) - 50;<br></br> ]]><br></br> </jsp:scriptlet><br></br> <day><br></br> <num><jsp:expression>i</jsp:expression></num><br></br> <compa><jsp:expression>compa</jsp:expression></compa><br></br> <compb><jsp:expression>compb</jsp:expression></compb><br></br> </day><br></br> <jsp:scriptlet><br></br> <![CDATA[ }<br></br> ]]><br></br> </jsp:scriptlet><br></br> </days><br></br> </jsp:root></span>
这个服务会每三十天为两家公司(compa 和 compb)导出一些随机的股票数据。第一家公司的数值从 1000 美元开始,第二家从 900 美元开始,而 JSP 代码会每天为这两个数值增加一个随机数。
当我从命令行使用 curl 客户端去访问这个服务时,我获得的是下面这样的结果:
<span color="#008000"> % curl "http://localhost:8080/jsp-examples/flexds/xml.jsp"<br></br> <days><day><num>0</num><compa>966.429108587301</compa><br></br> <compb>920.7133933216961</compb><br></br> </day>...</days></span>
根标签是
构建界面
现在我们已经有了一个 web 服务来输出股票的价格,我们还需要一个客户端应用来展现它。我们要构建的第一个界面是表格风格的界面,用它来简单的显示数字。为了创建 Flex 项目,我们在 Flex Builder IDE 的新建菜单中选择 Flex Project。显示如图 1:
图 1. 新 Flex 项目对话框
在这我们要做的就是给项目起个名字。我把它叫做 xmldg,意思是 XML 数据表格。这样就会创建出一个名叫 xmldg.mxml 的文件,其中只包含一个空白标签。下面我会使用列表 2 中的代码来代替这个空白标签。
<span color="#008000"><b> 列表 2. xmldg.mxml</b><br></br></span><span color="#008000"><?xml version="1.0" encoding="utf-8"?><br></br></span> <span color="#0000ff"><mx:Application</span> <span color="#008000"> xmlns:mx="</span><span color="#800080">http://www.adobe.com/2006/mxml</span>" <span color="#008000">layout=</span><span color="#800080">"vertical"></span> <span color="#008000"><mx:XML source=</span>"<span color="#800080">http://localhost:8080/jsp-examples/flexds/xml.jsp"</span> <span color="#008000">id=</span><span color="#800080">"stockData"</span> /> <span color="#0000ff"><mx:Panel</span> <span color="#008000">title=</span><span color="#800080">"Stock Data"</span> <span color="#008000">width=</span><span color="#800080">"100%"</span> <span color="#008000">height=</span><span color="#800080">"100%"</span>> <span color="#0000ff"><mx:DataGrid</span> <span color="#008000">dataProvider="{stockData..day}"</span> <span color="#008000">width=</span><span color="#800080">"100%"</span> <span color="#008000">height=</span><span color="#800080">"100%"</span>> <span color="#0000ff"><mx:columns><br></br><mx:DataGridColumn</span> <span color="#008000">dataField=</span><span color="#800080">"compa"</span> /> <span color="#0000ff"><mx:DataGridColumn</span> <span color="#008000">dataField=</span><span color="#800080">"compb"</span> /> <span color="#0000ff"></mx:columns><br></br></mx:DataGrid><br></br></mx:Panel><br></br></mx:Application></span>
xmldg 应用程序代码有两个主要的组件。第一个是 mx:XML 标签,它告诉 Flex 这是个 XML 数据源,并提供了 URL。这样就会创建一个叫做 stockData(由 id 属性指定)的局部变量,而 mx:DataGrid 组件可以把它当作 dataProvider 来使用。
代码的剩余部分就是界面了。 mx:Panel 对象为表格提供了一个简洁的包装。而 mx:DataGrid 用来显示数据。在 mx:DataGrid 中,是一串 mx:DataGridColumn 对象,来告诉表格显示什么数据。
如果我们从 Flex Builder 运行这个界面,你就会看到像图 2 的这个样子:
图 2. xmldg 应用运行界面
我们可以拉动滚动条,改变窗口大小,并且看到数据表格也会改变大小。如果需要添加一点过滤的功能,我们就需要使用 mx:HSlider 控件来更新代码,为它添加一个水平的滑块,来指定表格从哪一天开始显示数据。
比如,如果我们设置滑块到 6,它就会只显示从第六天开始的数据。代码如列表 3 所示:
<span color="#008000"><b> 列表 3. xmldg2.mxml</b><br></br><?xml version="1.0" encoding="utf-8"?></span> <span color="#0000ff"><mx:Application</span> <span color="#008000">xmlns:mx="<span color="#800080">http://www.adobe.com/2006/mxml"</span> layout="<span color="#800080">vertical</span>"><br></br><mx:XML source="http://localhost:8080/jsp-examples/flexds/xml.jsp" id="stockData" /><br></br><span color="#0000ff"><mx:Panel</span> title="<span color="#800080">Stock Data</span>" width="<span color="#800080">100%</span>" height="<span color="#800080">100%</span>" layout="<span color="#800080">vertical</span>"<br></br> paddingBottom="<span color="#800080">10</span>" paddingLeft="<span color="#800080">10</span>" paddingRight="<span color="#800080">10</span>" paddingTop="<span color="#800080">10</span>"></span> <b><span color="#008000"><mx:HBox><br></br><mx:Label text=</span><span color="#ff0000"><b>"Start Day"</b> /><br></br><span color="#0000ff"><mx:HSlider</span> <span color="#008000">minimum=</span>"0" <span color="#008000">maximum=</span>"30" <span color="#008000">id=</span>"dayslider" <span color="#008000">snapInterval</span>="1" /><br></br><span color="#008000"></mx:HBox></span></span></b><span color="#ff0000"><p><span color="#0000ff"><mx:DataGrid</span> <b>dataProvider="{stockData..day.(num >= daySlider.value )}"</b></p></span> <span color="#008000">width=</span>"<span color="#800080">100%</span>" <span color="#008000">height=</span>"<span color="#800080">100%</span>"> <span color="#0000ff"><mx:columns><br></br><mx:DataGridColumn</span> <span color="#008000">dataField=</span>"<span color="#800080">num</span>" <span color="#008000">headerText=</span>"<span color="#800080">day</span>" /> <span color="#0000ff"><mx:DataGridColumn</span> <span color="#008000">dataField=</span>="<span color="#800080">compa</span>" <span color="#008000">headerText=</span>"<span color="#800080">Company A</span>" /> <span color="#0000ff"><mx:DataGridColumn</span> <span color="#008000">dataField=</span>="<span color="#800080">compb</span>" <span color="#008000">headerText=</span>"<span color="#800080">Company B</span>" /> <span color="#0000ff"></mx:columns><br></br></mx:DataGrid><br></br></mx:Panel><br></br></mx:Application></span>
还有其他的一些标签,但规则基本上还是一样的。 mx:Panel 标签可以包含所有内容。其中可以是 mx:HBox (水平 格)标签,并且 box 还包含着 mx:Label 和 mx:HSlider 控件。slider 用于 mx:DataGrid 的 dataProvider 字段。
让我们来更进一步看看 dataProvider 属性:
<span color="#008000">{stockData..day.(num >= daySlider.value )}</span>
这里使用的是 ActionScript 的 E4X 语法来减少 mx:DataGrid 控件的数据集合,使其只包含那些
当我们从 Flex Builder 运行这个界面时,它看起来就像是图 3 这样:
图 3. 可过滤性网格
我们可以调整滑块的位置,并查看到表格中的数据如何变化。图 4 显示的是我把滑块设到 12 时的样子:
图 4. 滑块设为 12 时的显示界面
这只是个使用 ActionScript 中 E4X 的简单例子。E4X 语法使得处理 XML 变得非常容易,以至于你不会再愿意使用任何其他办法来处理 XML 了。
画图表
数据表格有点让人厌倦了,至少对我来说是这样。我喜欢有图像的。那么让我们来干点什么——在界面上放置一张图表。我们创建了一个新的名叫 xmlgph(意思是 XML 图表)的项目,并用列表 4 中的代码来代替自动生成的 xmlgph.xml 文件。
<span color="#008000"><b> 列表 4. xmlgph.mxml</b><br></br> <?xml version="1.0" encoding="utf-8"?><br></br><span color="#0000ff"><mx:Application</span> xmlns:mx="http://www.adobe.com/2006/mxml" layout="<span color="#800080">vertical</span>"><br></br> <mx:XML source="<span color="#800080">http://localhost:8080/jsp-examples/flexds/xml.jsp</span>" id="<span color="#800080">stockData</span>" /><br></br><span color="#0000ff"><mx:Panel</span> title="<span color="#800080">Stock Data</span>" width="<span color="#800080">100%</span>" height="<span color="#800080">100%</span>" layout="<span color="#800080">vertical</span>"<br></br> paddingBottom="<span color="#800080">10</span>" paddingLeft="<span color="#800080">10</span>" paddingRight="<span color="#800080">10</span>" paddingTop="<span color="#800080">10</span>"><p><span color="#0000ff"><mx:HBox><br></br> <mx:Label</span> text="<span color="#800080">Start Day</span>" /></p><br></br><span color="#0000ff"><mx:HSlider?</span> minimum="<span color="#800080">0</span>" maximum="<span color="#800080">30</span>" id="<span color="#800080">dayslider</span>" snapInterval="<span color="#800080">1</span>" /><p><span color="#0000ff"></mx:HBox></span><b><span color="#0000ff"><mx:LineChart</span> id="<span color="#800080">chart</span>" dataProvider="{stockData..day.(num >= daySlider.value )}"<br></br> width="<span color="#800080">100%</span>" height="<span color="#800080">100%</span>"><br></br> <mx:series><br></br><span color="#0000ff"><mx:LineSeries</span> xField="<span color="#800080">num</span>" yField="<span color="#800080">compa</span>" displayName="<span color="#800080">Company A</span>" /><br></br><span color="#0000ff"><mx:LineSeries</span> xField="<span color="#800080">num</span>" yField="<span color="#800080">compb</span>" displayName="<span color="#800080">Company B</span>" /><br></br> </mx:series><br></br> </mx:LineChart><br></br><span color="#0000ff"><mx:Legend</span> dataProvider="{chart}" /></b></p></span> <span color="#0000ff"> </mx:Panel><br></br> </mx:Application></span>
代码就跟 xmldb2 一样,但 mx:LineChart 控件替代了 mx:DataGrid 控件,用来显示一张数值图表, 而不是一个表格。另外还有个 mx:Legend 控件来显示不同颜色线条代表的公司名称。而两 个 mx:LineSeries 对象就类似于 mx:DataGridColumn 的功能。它们让线性图表知道在哪个轴上显 示什么数据。
当我们从 Flex Builder 运行这个界面是,看到的会是图 5 这个样子:
图 5. 线形图例
还不错吧?因为 mx:HSlider 控件还在那里,所以我们可以移动滑块的位置来改变图表的起始日期。
事实上,只需要一点点小的改变,我们就可以为用户在滑块上提供两个滑动杆,这样它们就能独立移动来让这个图表只显示一段日期内的数据。代码显示如列表 5 所示:
<span color="#008000"><b> 列表 5. xmlgph2.mxml</b><br></br> <?xml version="1.0" encoding="utf-8"?><br></br><span color="#0000ff"><mx:Application</span> xmlns:mx="<span color="#800080">http://www.adobe.com/2006/mxml</span>" layout="vertical"><br></br> <mx:XML source="<span color="#800080">http://localhost:8080/jsp-examples/flexds/xml.jsp</span>" id="<span color="#800080">stockData</span> " /><br></br><span color="#0000ff"><mx:Panel</span> title="<span color="#800080">Stock Data</span> " width="<span color="#800080">100%</span> " height="<span color="#800080">100%</span> " layout="<span color="#800080">vertical</span> "<br></br> paddingBottom="<span color="#800080">10</span> " paddingLeft="<span color="#800080">10</span> " paddingRight="<span color="#800080">10</span> " paddingTop="<span color="#800080">10</span> "><p><span color="#0000ff"><mx:HBox><br></br> <mx:Label</span> text="<span color="#800080">Date Range</span> " /></p><br></br><span color="#0000ff"><mx:HSlider</span> minimum="<span color="#800080">0</span> " maximum="<span color="#800080">30</span> " id="<span color="#800080">daySlider</span> " snapInterval="<span color="#800080">1</span> "<br></br><span color="#ff0000"><b>thumbCount="2 " values="[0,30]</b></span> " /><p><span color="#0000ff"></mx:HBox></span><span color="#0000ff"><mx:LineChart</span> id="<span color="#800080">chart</span>"</p><br></br><span color="#ff0000"><b>dataProvider="{stockData..day.(num>=daySlider.values[0] &&<br></br> num<=daySlider.values[1])}</b></span>"<br></br> width="<span color="#800080">100%</span>" height="<span color="#800080">100%</span>"><br></br><span color="#0000ff"><mx:series><br></br> <mx:LineSeries</span> xField="<span color="#800080">num</span>" yField="<span color="#800080">compa</span>" displayName="<span color="#800080">Company A</span>" /><br></br><span color="#0000ff"><mx:LineSeries</span> xField="<span color="#800080">num</span>" yField="<span color="#800080">compb</span>" displayName="<span color="#800080">Company B</span>" /><br></br><span color="#0000ff"></mx:series><br></br> </mx:LineChart><br></br> <mx:Legend</span> dataProvider="{chart}" /></span> <span color="#0000ff"> </mx:Panel><br></br> </mx:Application></span>
我们需要做的就是为 mx:HSlider 标签添加 thumbCount 和 values 属性,并更 新 mx:DataGrid 标签中的 dataProvider。因为这是段 XML,我必须对 dataProvider 中的部分实体进行编 码。如果从 Flex Builder 运行这段代码,我们会看到图 6 显示的那样:
图 6. 窗口型线形图
以上这些就是范例演示的 XML 部分。下面开始我会演示如何构建一个能调用 JSON 服务的 Flex 应用程序。
构建 JSON 服务器
我们由创建一个 JSON 数据源作为开端,来创建 JSON 阅读应用程序。同样,我们还是使用可靠的 JSP 来给构建 JSON 编码的数据流。这段服务器上的 JSP 代码显示如列表 6:
<span color="#008000"> 列表 6. json.jsp<br></br> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="1.2"><br></br> <jsp:directive.page import="java.text.*"/><br></br> <jsp:directive.page import="java.lang.*"/><br></br> <jsp:directive.page contentType="text/json"/><br></br> [<jsp:scriptlet><br></br> <![CDATA[<br></br> double compa = 1000.0;<br></br> double compb = 900.0;<br></br> for (int i = 0; i<=30; i++) {<br></br> compa += ( Math.random() * 100 ) - 50;<br></br> compb += ( Math.random() * 100 ) - 50;<br></br> if ( i > 0 ) out.print( "," );<br></br> ]]> </jsp:scriptlet>{"compa":<jsp:expression>compa</jsp:expression>,"compb":<jsp:expres<br></br> sion>compb</jsp:expression>}<jsp:scriptlet><br></br> <![CDATA[ }<br></br> ]]><br></br> </jsp:scriptlet>]<br></br> </jsp:root></span>
这就跟 XML 服务一样,但我们创建的不是 XML 标签,而是 JSON 编码的数据。
当我从命令行运行 curl 时,得到的页面如下所示:
<span color="#008000"> % curl "http://localhost:8080/jsp-examples/flexds/json.jsp"<br></br> [{"compa":992.2139849199265,"compb":939.89135379532}, ...]</span>
而这恰恰是 JavaScript 客户端能够理解的东西。
使用 JSON 服务
Flex 是用 Flash 播放器的编程语言 ActionScript 3 编写的。它和 JavaScript 很类似,但它没有 eval 方法。那么我们如何将 JSON 文本转换成 ActionScript 数据呢?幸运的是,免费的 ActionScript 3 核心库 ( http://as3corelib.googlecode.com ) 包含了 JSON 解码器和 JSON 编码器。
列表 7 中的代码演示了 JSONDecoder 对象的用法:
<span color="#008000"><b> 列表 7. jsondg.mxml</b><br></br> <?xml version="1.0" encoding="utf-8"?><br></br><span color="#0000ff"><mx:Application</span> xmlns:mx="<span color="#800080">http://www.adobe.com/2006/mxml</span>" layout="vertical"<br></br> creationComplete="jsonservice.send()"><br></br> <mx:Script><br></br> <![CDATA[<br></br><span color="#0000ff">import</span> mx.rpc.events.ResultEvent;<br></br><span color="#0000ff">import</span> com.adobe.serialization.json.JSONDecoder;<p><span color="#0000ff">private</span> function onJSONResult( event:ResultEvent ) : <span color="#0000ff">void</span> {</p><br></br><span color="#0000ff">var</span> data:String = event.result.toString();<br></br> data = data.replace( /\s/g, '' );<br></br><span color="#0000ff">var</span> jd:JSONDecoder = <span color="#0000ff">new</span> JSONDecoder( data );<br></br> dg.dataProvider = jd.getValue();<br></br> }<br></br> ]]><br></br> </mx:Script><br></br><span color="#0000ff"><mx:HTTPService</span> id="<span color="#800080">jsonservice</span>"<br></br> url="<span color="#800080">http://localhost:8080/jsp-examples/flexds/json.jsp</span>"<br></br> resultFormat="<span color="#800080">text</span>" result="onJSONResult(event)" /><br></br><span color="#0000ff"><mx:Panel</span> title="<span color="#800080">Stock Data</span> " width="<span color="#800080">100%</span> " height="<span color="#800080">100%</span> "><br></br><span color="#0000ff"><mx:DataGrid</span> id="<span color="#800080">dg</span>" width="<span color="#800080">100%</span>" height="<span color="#800080">100%</span>"><br></br><span color="#0000ff"><mx:columns><br></br> <mx:DataGridColumn</span> dataField="<span color="#800080">compa</span> " /><br></br><span color="#0000ff"><mx:DataGridColumn</span> dataField=</span>"<span color="#800080">compb</span> " /> <span color="#0000ff"> </mx:columns><br></br> </mx:DataGrid><br></br> </mx:Panel><br></br> </mx:Application></span>
因为服务器返回的是 JSON 文本,我们无法使用 mx:XML 标签来取得数据。因此我们用的 是 mx:HTTPService 标签。它的工作原理跟 mx:XML 很像。你需要给它一个服务的 URL,并且告诉它结果的 格式(比如文本)以及 HTTP 服务发回响应数据时需要调用的 ActionScript 方法。
在这个例子中,我为结果处理方法指定的是在 mx:Script 标签中定义的 onJSONResult 方法。这个方法会去掉所有空格,并把 JSON 文本传递给 JSONDecoder 对象。接着它将 mx:DataGrid 控件的 dataProvider 设置成 JSONDecoder 返回的处理结果。
所有这些都是安全的,因为 ActionScript 不支持 eval 方法。JSONDecoder 类是个简单状态机解析器,来实时地从文本构建出对象。最糟糕的情况可能是这样的过程会需要一段比较长的时间,如果 JSON 文本太大的话。
下面干什么
Flex 是基于 Flash 的,而 Flash 可以跟任何技术进行交互。它可以直接与基于 SOAP 的 web 服务交互。它甚至能跟 AMF(Adobe Message Format)这样的协议进行二进制数据的通信。
如果这是你第一次使用 Flex,你可能会想着如何用 Flex 来构建一个 Flash 小部件,放到自己的网站上以更吸引人的方式来显示数据。为了确保 Flash 应用的尺寸足够小方便下载,记得一定要使用新版本 Flash 播放器中的运行时共享库(Runtime Shared Library,RSL)。这可以让你在客户端缓存大尺寸的库(比如 Flex 库),并在不同的 Flash 应用中重用这些库。
Flex 和 Java 是一个强大的组合。Java 提供了优秀的的服务器后端支持。而 Flex 和 ActionScript 3 提供的是一个易于编写和采用的通用跨平台的 GUI 层。
查看英文原文: Flex for XML and JSON 。
给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。
评论