当前位置: 代码迷 >> Web前端 >> 应用 Flex 和 Dojo 开发交互式Web应用程序
  详细解决方案

应用 Flex 和 Dojo 开发交互式Web应用程序

热度:649   发布时间:2012-11-01 11:11:33.0
使用 Flex 和 Dojo 开发交互式Web应用程序

引言

以用户体验为核心的交互式 Web 应用程序在行业解决方案中是必不可少的一部分,新兴的 Ajax 技术和 Flex 技术都能使开发人员更便捷地创建出色的富 Internet 应用程序(RIA)。Dojo 作为 Ajax 技术的代表,是目前最为强大的 JS 框架之一,它提供了极其完备的可调用库,而且受到 IBM 的支持并在 IBM 产品中广泛使用;Flex 则是通过为开发人员提供面向对象编程的方式来描述应用的外观和行为。


Flex 和 Dojo 介绍

Flex 通过为开发人员提供面向对象编程方式,借助相比 HTML 更加规范化、标准化的 MXML 语言来描述应用的外观和行为,最后由 MXML 与 ActionScript 编译生成 swf 文件融合到 Web 客户端里面。正因为 Flex 偏向于开发人员,而且包含了丰富的组件库,所以更容易让开发人员创建出色的富 Internet 应用程序。下面简单介绍一下 Flex 中的两个关键技术:

  • MXML 是一种基于 XML 的用户界面标记语言,主要用于对 Flex 应用程序进行布局并向其添加组件,MXML 还用于对服务器端数据源的访问以及用户界面组件和数据源之间的数据绑定。它允许开发人员创建动画、状态、转换和样式,并且具有很好的可扩展性,允许开发人员方便地创建可重用组件。
  • ActionScript 是基于 ECMAScript 的脚本编制语言,在 Flex 中,ActionScript 允许您为应用程序增添交互性。

Dojo 是一个面向对象,开源的 JavaScript 工具箱。它为开发 Web 富客户端程序提供了一套完整的 Widget 和一些特效操作。

根据 Flex 和 Dojo 各自的特性和优势,为了更好的满足用户的需求,提供良好的用户体验,本文讲述的交互式 Web 应用程序将采用以下策略,其中针对交互性更强的图片处理部分将通过 Flex 实现,而对实时性要求更高的图片、文本信息更新和交互部分则通过 Dojo 来实现。

应用程序模型及交互模式

在传统的三层体系结构中,可以看到无论是业务逻辑层产生变化,还是对数据库进行改变都不会对这两者中的另一层产生影响或者只产生很细微的影响,可以说数据库和编程语言基本上完成了解耦;但是进一步思考,会清晰的发现这样一个问题,当外界需要系统对业务逻辑层进行的升级或改变时,会直接导致现有的表现层几乎彻底的改变,这一问题在传统的三层体系结构下无法避免。

RIA 的出现可以在很大程度上改变这一缺陷。这是因为一方面在 RIA 应用程序模型中,可以将业务功能进行封装,并以服务的方式提供给客户端,客户端不管是 JavaScript,Dojo 或者是 Flex 都不需要关注功能的实现,而只是去专注于用户的交互体验;另一方面,RIA 应用程序的客户端仅由浏览器和插件构成,用户界面高度的统一,应用的升级、改变对用户几乎毫无影响,用户无需对客户端进行升级、扩展等操作。本文将沿用现有 RIA 应用程序的模型,如下所示:


图 1. 应用程序模型
图 1. 应用程序模型

为了达到表现层和服务器端动态交互的目的,这里所采用的方式是:由 Flex Builder 编译生成的 SWF 文件可以通过 AMF 协议方式或 XML 方式为 FlashPlayer 与服务器端提供一种高性能的访问方式;而 Dojo 则是通过 JSON-RPC 来异步调用服务器端 Java 对象。具体的实现方式会在接下来的实例中具体阐述。

开发环境

Flex Builder3.0, 服务器 IBM WebSphere V6.1 Server,当然也可以使用其他 J2EE 服务器。


构建基于 Flex 的图片处理应用程序

本图片处理应用程序创建一个 Canvas 组件,用于显示用户在图片列表中选中的图片,对于在 Canvas 组件中显示的图片,提供图片放大缩小及图片拖拽的功能。接下来将详细介绍这个基于 Flex 图片处理应用程序的实现步骤:

创建新的 Flex 应用程序

打开 Flex Builder 工具,在菜单中选择 File -> New -> Flex Project创建一个新的 Flex 工程,其他选项如下图所示:


图 2. 创建应用程序
图 2. 创建应用程序

点击 Finish按钮后完成创建步骤。在 Flex Development 视图下,可以看到新建的项目结构如下所示:


图 3. Flex 应用程序文件结构
图 3. Flex 应用程序文件结构

其中值得注意的是建议大家在编译 Flex 项目时,将该应用程序的文件放到 bin-debug 文件夹下,作为项目开发的输出目录;当准备部署应用程序时,把部署文件生成到指定的部署目录 bin-release 中。在本交中,会将部署成功的 SWF 文件嵌入到 Web 项目中,具体做法会在 2.4 章节中详细讲述。

创建图片处理用户界面

在图 3 中可以看到 src 目录下有一个 MXML 文件,这个主应用程序 MXML 包含了所有的 UI 组件和向外部暴露的接口,为了体现项目的易扩展性,可以将 Script 实现的具体功能作为一个图片处理的组件封装在一个新的 MXML 文件(ImageZoom.mxml)中,然后将这个图片处理组件绑定到主应用程序中去。


清单 1. ImageZoom.mxml

				 
 <?xml version="1.0" encoding="utf-8"?> 
 <Canvas 
 xmlns=http://www.adobe.com/2006/mxml xmlns:flash.filters="flash.filters.*"
 creationComplete="onCreationComplete()" horizontalScrollPolicy="off" verticalScrollPolicy="off" 
 mouseWheel="onMouseWheel(event)" > 
 <Script> 
 // 图片处理功能具体实现
 </Script> 
 <Zoom id="zoomEffect" target="{image}" duration="100"
 zoomHeightTo="1" zoomWidthTo="1" effectEnd="onEffectEnd()" 
 easingFunction="{zoomEasingFunction}"/> 
 <Move id="moveEffect" target="{image}" easingFunction="{moveEasingFunction}" /> 
 <Canvas id="maskCanvas" backgroundColor="#FF0000" width="100%" height="100%"/> 
 <Image id="image" mask="{maskCanvas}" source="{_source}" height="420"
  mouseDown="startImageDrag()" mouseMove="undoOutside()" complete="imageComplete()"
   doubleClickEnabled="true" 
 visible="{_source != null image.percentLoaded == 100}"/> 
 </Canvas> 

?

ImageZoom.mxml 组件包含一个含有脚本块的 Flex Canvas,脚本包含了图片处理功能具体的实现,一个子 Canvas 组件和 Image 组件,该 Image 组件详细定义了组件外观大小,图片信息来源和初始化函数并指定了 mouseDown, mouseMove 等事件的响应函数。


清单 2. FirstFlexProject.mxml 片段

				 
 <ImgZomm:ImageZoom 
 id="zoomComponent" borderStyle="solid" source="{}" bottom="0" left="0" 
 top="0" right="0" zoomIncrement="0.2" imageDoubleClickEnabled="true" 
 mouseWheelEnabled="false" mouseFollow="true" mouseUp="showMouseEvent(event)"
 /> 
 <VSlider id="brightnessValue" alpha="0" minimum="-100" maximum="100" 
 snapInterval="1" value="0" height="120" liveDragging="true" x="7" y="96"
  dataTipFormatFunction="degrees_func_Brightness" 
 buttonMode="true" useHandCursor="true"/> 
 <Button id="zoomInButton" alpha="0" icon="@Embed('/theme/Icons_02.gif')"
  click="imgZoomIn(true)" top="395" height="16" width="16" 
 toolTip="Zoom In" useHandCursor="true" buttonMode="true" left="136"/> 

?

清单 2 列举的 FirstFlexProject.mxml 片段表明主应用程序 MXML 组件包括了一个 ImageZoom 组件来显示整个图片区域,两个 VSlider 组件用游标拖动的方式在自定义图片的对比度和明暗度,一个 HSlider 组件用游标拖动的方式对图片进行缩放处理并响应以其他方式完成的缩放图片,四个 Button 分别完成点击按钮放大缩小图片和重置功能。

这样,整个图片处理应用程序的用户界面就构建完成了,如下图所示:


图 4. 图片处理程序用户界面
图 4. 图片处理程序用户界面

加入操作支持事件响应

在实际应用系统中,人机交互是必不可少且非常重要的一部分,如何对用户触发的事件进行有效的响应是 Flex 应该解决的重点问题之一,下面将通过一个具体功能的实现来介绍三种常见的交互模式,鼠标事件响应、键盘事件响应和控件触发事件的响应。

图片缩放功能是本图片处理应用程序的主要功能,它主要提供了三种交互模式完成图片局部放大缩小的功能,包括支持鼠标左右键单击放大缩小,支持键盘快捷键放大缩小以及点击 Flex 控件完成放大缩小。

首先来看一下在 Flex 中实现放大缩小的功能,封装在 ImageZoom.mxml 文件中,代码如下:


清单 3. Flex 中实现图片缩放功能

				 
 1  public function zoom( factor : Number, isButton : Boolean ) : void 
 2  { 
 3    if(!isAnimating ){ 
 4      isAnimating = true; 
 5      if(zoomEffect.isPlaying ){ 
 6        zoomEffect.end(); 
 7      } 
 8      if(factor <= 5 && factor >= -5){ 
 9         if((isButton && zoomEffect.originX.toString() == 'NaN'
            &&zoomEffect.originY.toString() == 'NaN')|| flag == true && 
            isButton){ 
 10             zoomEffect.originX = image.contentWidth/2; 
 11             zoomEffect.originY = image.contentHeight/2; 
 12         } 
 13         flag = false; 
 14         scale_temp = factor; 
 15         if(scaleSize[factor+5] > 1){ 
 16           zoomEffect.zoomHeightTo = Math.max(temp + scaleSize[factor+5], minScale); 
 17           zoomEffect.zoomWidthTo = Math.max(temp + scaleSize[factor+5], minScale); 
 18    }else if(scaleSize[factor+5] < 1){ 
 19      zoomEffect.zoomHeightTo=Math.max(temp - temp*(1-scaleSize[factor+5]), minScale); 
 20      zoomEffect.zoomWidthTo=Math.max(temp - temp*(1-scaleSize[factor+5]), minScale); 
 21      }else{ 
 22        zoomEffect.zoomHeightTo = Math.max(temp, minScale); 
 23        zoomEffect.zoomWidthTo = Math.max(temp, minScale); 
 24      } 
 25    } 
 26      zoomEffect.play(); 
 27      this.dispatchEvent(new Event(EVENT_SCALE_UPDATED)); 
 28    } 
 29  } 

?

这段代码有几个要点,第一,会根据 isButton 参数和 zoomEffect.originX 的值来判断图片放大缩小的焦点位置,如果满足如第 9 行 code 所列举的条件则按照图片中心位置进行缩放,否则按照鼠标点击位置进行缩放;第二,图片缩放的倍数值事先配置到数组 scaleSize[] 中,然后会根据 factor 参数指定具体的缩放倍数。

为了提高应用程序和用户的交互性,势必需要满足客户的如下要求:

  • 鼠标左键点击图片放大,右键点击图片缩小
  • 鼠标左键点击保持时可拖拽图片

为了实现这样的功能,需要克服两个障碍:第一,屏蔽 Flex 右键菜单并捕获鼠标右键点击事件;第二,区分图片拖拽和图片缩放功能。为此,将采用的解决办法如下:

  • 在 Flex 应用程序中定义一个接口函数接收用户右键点击事件,并用 mouseUp 处理函数实现这个鼠标事件函数;另一方面,在 JSP 代码中阻止鼠标右键事件向下传递并调用 Flex 外部函数。

至此,一个简单的 Flex 应用程序就构建完毕了,接下来可以将这个 Flex 应用程序集成到 Web 项目中。

如何与 Web 项目的集成

首先,在 Flex Builder 中通过选择 Project -> Export Release Build来生成图片处理程序的 SWF 部署文件。接下来讲解如何将这个 SWF 文件与 Web 项目集成,并在 JSP 中调用 Flex 程序所提供的功能,具体的事例如下:

在某些具体的应用场景中,可能需要针对一组图片列表中的某张图片提供图片处理的功能,这样就存在一个问题,如何将图片应用到基于 Flex 的图片处理程序中去。

在这里,所采用的处理方式如下:将图片作为输入源,通过调用图片处理程序向外暴露的接口,以参数传递的方式将图片文件应用到 Flex 程序中,这就需要从两方面着手工作:

一方面,需要在 Flex 应用程序中利用外部接口注册一个函数,作为接收 JSP 中图片选择事件的一个入口,具体实现代码如下:


清单 4. FirstFlexProject.mxml 中显示所选图片功能实现

				 
 ExternalInterface.addCallback(“getValue”, getImgValue); 
 private function getImgValue(imgURL:String):Boolean { 
 var returnMsg:Boolean; 
 if(zoomComponent.image.source != imgURL) 
 { 
 zoomComponent.image.load(imgURL); 
 application.setFocus(); 
 } 
 return returnMsg; 
 } 

?

清单 4 分为两部分,第一行是利用外部接口方式注册了一个函数,提供给 JSP 去调用;后面的 getImgValue() 方法则是通过调用 SWFLoader.as 文件中 load 方法的方式从文件目录中加载图片信息。

另一方面,需要在 JSP 中调用所开发的 Flex 应用程序以及其向外暴露的接口。清单 5 说明了如何在 JSP 中定义 Flex 应用程序实例,值得注意的是使用 src 属性指定所调用的 Flex 应用程序,使用 id 属性将实例的 ID 传给 Flex 应用程序。还应该注意到 wmode 这个属性,它的默认值是 Window,表明 Flash 应用程序与 HTML 层没有任何的交互,并且始终位于最顶层,而在应用中实现了 Flash 上添加浮层,所以将此属性值改为 Opaque。清单 6 简单说明了如何调用 Flex 中所实现的“显示所选图片”功能的接口。


清单 5. JSP 中定义 Flex 程序实例

				 
 <td colspan="4" valign="top" id="imgFlex" onmouseup="whichElement(event)"> 
 <script language="JavaScript" type="text/javascript"> 
 AC_FL_RunContent( 
"src","<%=request.getContextPath()%>/theme/FirstFlexProject", 
"width", "100%", 
"height", "420","align", "middle", 
"id", "ImageObj", 
"quality", "high", 
"name", "ImageObj", 
"wmode", "opaque", 
"allowScriptAccess","sameDomain", 
"type", "application/x-shockwave-flash"
"pluginspage", "http://www.adobe.com/go/getflashplayer"
 ); 
 </script> 
 </td> 



清单 6. JavaScript 中调用 Flex 程序所提供的接口

				 
 function SendImg(value) { 
 if(value !=""){ 
 dojo.byId('ImageObj').getValue(value); 
 } 
 } 

?

通过上述的几段代码的定义和调用,就能实现从 JSP 页面调用 Flex 程序提供的功能,从而将图片应用到基于 Flex 的图片处理程序中。


Dojo 在交互式 Web 程序中的应用

在交互式 Web 应用系统中,性能是一个不可忽视的重要因素,特别是用户处理的响应时间往往更容易被关注。因此,在图片加载,文本信息更新以及和后台服务交互这些能充分体现出实时性和交互性的部分,可以选择更具优势的 Dojo 技术来实现。

本部分同样会根据一个实例来详细讲解以下三个方面的内容:如何在 Web 客户端中使用 Dojo 控件,如何在 Dojo 控件和 JSP 页面之间进行交互,如何在客户端和后台服务之间进行消息传递和函数调用。

如何使用 Dojo 控件

Dojo 是一个非常强大的面向对象的 JavaScript 的工具箱,在此所下载的版本是 IBM1.2.3-20090331, 下载 dojo 的工具包,它包含有 4 个文件夹,分别是:

  • dojo 提供工具包的基本功能,如 CSS 功能吨的查询,事件处理,动画,Ajax,基于类的编程和包系统;
  • dijit 易于定制用户界面库;
  • dojox:主要是 2D 画图一类的;
  • uitl:主要是通用的方法类。

首先将所下载的 Dojo 包引入到 Web 工程中,具体位置如下图所示:


图 5. 项目基本结构及 Dojo 包引入位置示意图
图 5. 项目基本结构及 Dojo 包引入位置示意图

接下来的清单 8 和清单 9 举例说明了如何真正引用 Dojo 代码,从而可以直接使用 Dojo 中部分常用的对象。


清单 8. 引用 Dojo 的启动代码

				 
 <script type="text/javascript"
 src="/dojoroot/dojo/dojo.js" djConfig="parseOnLoad: true"> 
 </script> 

?

其中 djConfig 是 Dojo 里的一个全局对象 , 其作用就是为 dojo 提供各种选项 , isDebug 是最常用的属性之一 , 设置为 True 以便能够在页面上直接看到调试输出 , 当然其中还有些属性与调试有关。


清单 9. 申明你所要用到的包

				 
 <script type="text/javascript"> 
 dojo.require("dojo.math"); 
 dojo.require("dojo.io.*"); 
 dojo.require("dojo.widget.*"); 
 </script> 

?

通过 Dojo 静态引用的方式,可以把这些代码当成是 Java 的 import 语句一样。如果你不 require 的话 , 而模块本身又没有整合在 dojo.js 中 , 是会出现脚本错误的。

通过上述的引用以及对常用对象的使用,基本上就能完成大部分的信息展示或异步更新的功能。

Dojo 控件与页面及后台服务的交互

接下来要说明的是如何使用 Dojo 控件和 JSP 页面以及后台服务交互。假设所要实现的功能如下:在前台页面上实现一个跟后台服务的异步交互,然后在页面上弹出对话框的功能。

传统的方式需要提交 request 到后台后刷新页面,并且对话框焦点都会落在本身对话框上了,必须要先点击了对话框才能做别的操作,在本文中使用了 dojo 的 toaster 控件,它能在页面上弹出多个对话框,你还可以去做别的操作,当你点击某一个对话框时,被点击的那个会消失,并且页面不会进行刷新,增强了用户体验的多样性。

步骤一:在 JSP 页面中引用相应的包和相应的 dojo.js,申明中的第二句和第三句都是在与后台服务交互是所需要的。


清单 10. 申明并使用 toaster 控件

				 
 <script type="text/javascript"> 
 dojo.require("dojox.widget.Toaster"); 
 dojo.require("dojo.rpc.RpcService"); 
 dojo.require("dojo.rpc.JsonService"); 
 </script> 
 <script type="text/javascript" src="dojo.js" 
 djConfig="isDebug:true, parseOnLoad: true"> 
 </script> 
 <div dojoType="dojox.widget.Toaster" 
 id="toast" positionDirection="bl-up" duration="0"
  messageTopic="testMessageTopic"> 
 </div> 

?

这里面用到了几个 toaster 的属性:

positionDirection:指定了弹出的对话框在什么位置显示。

duration:消息显示的时间,0 意味着用户必须通过点击来确认消息。

messageTopic:消息主题的标识,当页面发布这个主题的消息时,讲弹出次对话框。

步骤二:在本例中首先要和后台交互,取得返回的消息,这些都是异步进行的,首先需要指定哪些后台类能通过 JSON-RPC 的方式进行调用,配置文件代码如清单 11 所示,其中 <pojo></pojo> 指定了某一个特定可以调用的后台类,如需要调用多个不同的类,只需添加对应的 <pojo></pojo> 即可:


清单 11. 在 web-inf 中加入 RpcAdapterConfig.xml

				 
 <rpcAdapter 
 xmlns="http://www.ibm.com/xmlns/prod/websphere/featurepack/v6.1/RpcAdapterConfig"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
 <default-format>xml</default-format> 
 <services> 
 <pojo> 
 <name>FirstService</name> 
 <implementation>com.mytest.dojotest.ToasterTest</implementation> 
 <description></description> 
 </pojo> 
 </services> 
 </rpcAdapter> 

?

步骤三:在页面 Javascript 中完成对后台服务的调用,如清单 12 所示:


清单 12. 在页面中调用后台的 doToasterServiceTestAction 方法

				 
 function clickToaster(){ 
 var dojoService = new dojo.rpc.JsonService("<%=request.getContextPath()%> 
 /RPCAdapter/jsonrpc/FirstService"); 
 dojoService.doToasterServiceTestAction().addCallback(getProcessActionResult); 
 } 

?

清单 12 中值得注意的是:dojo.rpc.JsonService 中的内容是拿到所需要调用的后台指定类的实例(上面的 config 配置文件中 name 属性指定的 ToasterTest 类),而 doToasterServiceTestAction() 是 ToasterTest 类的成员方法,它可以写一些具体的业务需求,这个例子里面是把一条字符串(Hello, Toaster !)信息通过回调方法传给 getProcessActionResult 方法,这个方法具体用到了 dojo 的 toaster 控件。

步骤四:在 JavaScript 中调用后台所返回的处理结果,并呈现在 UI 上


清单 13. 在 getProcessActionResult 中调用 toaster 控件

				 
 function getProcessActionResult(result,exception){ 
 processMessage = result; 
 dojo.publish("testMessageTopic", 
 [{ message: processMessage }] 
 } 

?

其中 dojo.publish 方法就调用了前面讲的 toaster 控件,此时在页面上点击“Click to show message”就会调用 clickToaster 方法。如下图 6-1 左下绿色部分所示,控制的消息显示出来了,此时你如果继续点击按钮就会出现如图 6-2 的效果。


图 6-1. toaster 控制页面
图 6-1. toaster 控制页面

图 6-2 .toaster 控制页面
图 6-2 .toaster 控制页面

这样,一个非常简单的 Dojo 与页面和后台交互的小例子就做完了,在实际的应用中当用户点击某一按钮的操作时,会发送请求到后台服务,根据请求的业务组装需要的结果,之后就会把相应的信息显示到页面上左下角的部分,每点击一下按钮就会增加一个对话框。


结束语

至此,通过基于 Flex 图片处理应用程序和使用 Dojo 控件这两个实例开发和集成的介绍,相信读者能充分认识到同时使用 Flex 和 Dojo 在企业内部或在 Web 上创建 RIA 程序的可行性,同时 Dojo 技术和 Flex 技术具有很强的互补性,通过讲解过程中所描述的场景,我们可以清晰的发现,在创建个性化的丰富多媒体应用程序,需要极强的交互式用户体验的时候,Flex 具有独特的优势,而在系统用户处理响应时间或性能等需要充分体现交互的实时性的领域,用 Dojo 技术来实现往往会将问题迎刃而解。

最后,我们相信同时使用 Flex 技术和 Dojo 技术,能够让企业能够创建个性化的丰富多媒体应用程序,极大地提高用户的体验,使得我们所开发的 web 客户端应用程序更加栩栩如生,彻底革新人与 Web 的交互关系。

<!-- CMA ID: 470167 --><!-- Site ID: 10 --><!-- XSLT stylesheet used to transform this file: dw-article-6.0-beta.xsl -->

?