Flex开发的一些经验总结——Remote Object篇

2011-04-06 22:54 by hackerzhou

我毕业设计的管理界面是使用Flex 4.0开发的(因为现在实习所在的UI Team使用的就是Flex,很多东西可以现学现用)。由于之前并没有很系统的学习过Flex,因此还是碰到了一些坎坷,写出来与大家分享下我的解决方案。这篇介绍的是如何使用和封装Remote Object调用以及简单的代码生成。

本文所叙述的Remote Object服务器框架是Adobe的开源框架BlazeDS,Adobe还有一套名叫LiveCycle Data Services ES2的框架,不过那是需要购买的。一般来说,开源的BlazeDS已经够用了,需要了解更多的差别参见官方的文档:https://www.adobe.com/cfusion/entitlement/index.cfm?e=lc_blazeds。配置和简单的示例本文不赘述,网上一堆的教程,搜搜便会。

所有的Code都可以在:http://hackerzhou.googlecode.com/svn/trunk/Java/ReflectProxy/中找到。

Remote Object基于事件的封装

以前在学校做自己的一些应用的时候都是用WebService来进行客户端和服务器的通信,没有用过基于AMF的RemoteObject技术,实习的时候用了一把RemoteObject,觉得相当的高效和方便。当然,如果直接在MXML中使用系统自带的RemoteObject支持,就跟使用HTTPService来进行WebService操作没啥两样了:都不能代码复用,相当不方便。因此,继续进行封装,封装成一个基于事件的异步RemoteObject调用框架(即进行异步的请求,从服务器返回后响应事件,调用某个指定的回调函数),还要能返回是否调用出错以及出错的信息。在查了Flex的doc之后找到了如下的类mx.rpc.AbstractOperation和mx.rpc.AsyncToken,在mx.rpc.http包下同样也有一个AbstractOperation类,不过那不是我们想要的。
RemoteObjectUtil源代码:

package me.hackerzhou.reflectproxy.ui.util
{
	import mx.controls.Alert;
	import mx.rpc.AsyncToken;
	import mx.rpc.CallResponder;
	import mx.rpc.Responder;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	import mx.rpc.AbstractOperation;
	import mx.rpc.remoting.mxml.RemoteObject;

	public class RemoteObjectUtil extends RemoteObject
	{
		public static const DEFAULT_DESTINATION:String = "UIDataServiceImpl";

		public function RemoteObjectUtil(destination:String = DEFAULT_DESTINATION) {
			super(destination);
		}

		public function call(methodName:String, callback:Function, ...args):void {
			var method:AbstractOperation = this.getOperation(methodName);
                        //为了方便起见,如果有多个参数的话就把参数包成一个Array,在J2EE端使用Object[]来获取参数
			method.arguments = args;
			var call:AsyncToken = method.send();
			call.userDefinedCallback = callback;
			call.addResponder(new Responder(resultCallback, faultCallback));
		}

		public function resultCallback(event:ResultEvent):void {
			var callback:Function = event.token.userDefinedCallback as Function;
			if (callback != null) {
				var result:RemoteObjectResult = new RemoteObjectResult();
				result.error = false;
				result.resultData = event.result;
				callback(result);
			}
		}

		public function faultCallback(event:FaultEvent):void {
			var callback:Function = event.token.userDefinedCallback as Function;
			if (callback != null) {
				var result:RemoteObjectResult = new RemoteObjectResult();
				result.error = true;
				result.errorMessage = event.fault.toString();
				callback(result);
			}
		}
	}
}

RemoteObjectResult源代码:

package me.hackerzhou.reflectproxy.ui.util
{
	import mx.rpc.events.FaultEvent;

	public class RemoteObjectResult
	{
		public var error:Boolean = false;
		public var errorMessage:String = null;
		public var resultData:Object = null;
	}
}

这样的话,当需要调用RemoteObject的时候只需要调用call(methodName:String, callback:Function, …args)这个函数,传需要调用的服务器端函数名称,调用完成后的回调函数(这个回调函数必须接受一个类型为RemoteObjectResult的参数),以及调用所需要的参数列表就可以非常简单方便的完成一次RemoteObject调用。比如:

var ro:RemoteObjectUtil = new RemoteObjectUtil();
ro.call("helloworld", helloworldCallback);
...
private function helloworldCallback(result:RemoteObjectResult):void{
   if(result.error){
       Alert.show(result.errorMessage);
       ...
   }else{
       var resultData:Object = result.resultData;
       ...
   }
}

简单的RemoteObject代码生成

由于RemoteObject技术实际上传递的是序列化过的对象,因此需要在服务器端和客户端维护近似的对象。比如J2EE端有对象User,Flex端也需要有对应的对象User。这样RemoteObject框架在中间就能起到转换的桥梁作用。比如我毕业设计中的Java类User和ActionScript类User,大家会发现在Flex需要用RemoteClass来制定远端(J2EE端)的对应对象。这个工作是高度重复的,因此利用Java的反射机制来生成Java Bean对应的ActionScript代码,具体可以查阅我的代码GenerateRemoteObjects.java,虽然不太精致,但至少凑合着能用。

另外,就上面封装的基于事件的Remote Object例子来说,有很多数据是没有必要每次都重新从服务器调用载入一遍的,比如某个列表,只有在对其增删改的时候需要触发refresh,其余的时候使用缓存中的数据,直到用户手动refresh。因此,我写了CachedData.as类管理用来作为绑定数据源的缓存数据以及对应的刷新方法。这种做缓存的机制是从现在在公司跟的项目中学到的,感觉还是很实用的。

为了更加方便的在Flex中调用Remote Object,在Flex端根据Java端定义的Service Method建立对应的Service Proxy,即所有与服务器的函数调用都必须经过Service Proxy,好处有很多,对我来说最大的好处是方便调试以及方便使用(因为可以用代码提示)。在Java端我还使用了Annotation来标记每个Service Method,指示是否需要Cache,代码生成的时候GenerateDataService.java会根据对应的Annotation选择是否写入CachedData.as,并生成所有Service的Service Proxy。

本文基于 署名 2.5 中国大陆 许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 hackerzhou 并包含 原文链接
发表评论

本文有 3 条评论

  1. Spring
    2012-02-20 11:44

    您好,google到这里,参考了您的RemoteObjectUtil 实现,并去了googlecode,没找到<s:RemoteObject的配置,请问<s:RemoteObject是在哪里配置的?

发表评论