在我之前的两篇文章Flex 性能提示 Ajax轮询以及Comet模式—写在Servlet 发布之前中我反复提到Adobe BlazeDS这个开源产品假设某天你在看了Flex 性能提示之后放弃了Flex+Servlet+XML方案那么如何进行下一步?本文试图用简单的表述来实践一回Java到Flex之间的对象透明传递所谓透明本人理解为不需要人工的(反)序列化在阅读本文之前你需要有一定的SpringBlazeDSFlex使用经验
我使用的是Eclipse Java EE平台和Tomcatx以及SQL Server 为了不脱俗选用了Spring(传说中的春天框架)外加最近才GA的Spring BlazeDS IntegrationPS其实不用春天框架也可以只是觉得他的JdbcDaoSupport很不错可以自己偷懒了而且连接池和JDBC驱动这些基础设施也allinone了另外要使用Spring BlazeDS Integration需满足它个愿望Java or higherSpring or higherAdobe BlazeDS or higher(推荐下载blazedsturnkey)我想这三个愿望在google上是很好实现的成品的项目结构是这样的对于如此简单的实践无需用到Service层
有了上面的目标接下来就很好办了首先创建名为JavaFlexMapping的动态Web项目接着导入blazedsturnkeyxxxxx\resources\lib下的所有jar至于Spring相关的jar你可以根据自己的经验导入也可以先导入springjar然后导入springwebmvcjar(Spring BlazeDS Integration需要)最后再把springframework\lib下的所有jar都导入进来这样干牺牲了磁盘空间但换来了更少的烦恼Spring BlazeDS Integration的orgspringframeworkflexRELEASEjar也导入进来吧这就算完成了部分包导入工作不过在实际使用中还会需要其他jarxalanjarbackportutilconcurrentjarjtdsjar(SQL Server JDBC驱动)如果在之后的实际操作中出现缺包情况Spring会在控制台说明的最后把blazedsturnkeyxxxxx 下的\tomcat\webapps\blazeds\WEBINF\flex文件全部拷贝到WEBINF下的flex目录中
Java程序的运行环境都配置好了看看表结构是怎样的
这是一个简单的表反映了组和五个组成员的信息
所有必要的资源准备完毕可以编码了先看VO类FlexGroupjava的内容
packageorgrosenjiangflex;
/**
*FlexGroupObject
*@authorrosenjiang
*@since//
*
*/
publicclassFlexGroup{
privateStringgroupName;
privateStringmember;
privateStringmember;
privateStringmember;
privateStringmember;
privateStringmember;
publicStringgetGroupName(){
returngroupName;
}
publicvoidsetGroupName(StringgroupName){
thisgroupName=groupName;
}
publicStringgetMember(){
returnmember;
}
publicvoidsetMember(Stringmember){
mber=member;
}
publicStringgetMember(){
returnmember;
}
publicvoidsetMember(Stringmember){
mber=member;
}
publicStringgetMember(){
returnmember;
}
publicvoidsetMember(Stringmember){
mber=member;
}
publicStringgetMember(){
returnmember;
}
publicvoidsetMember(Stringmember){
mber=member;
}
publicStringgetMember(){
returnmember;
}
publicvoidsetMember(Stringmember){
mber=member;
}
}
没啥好说的就是一个表结构的对象化表述不过有两个问题
既然牵涉到跨语言的对象传输为什么没实现序列化接口?
为了让自己和大家了解昨天我专门请教了据说是Sun公司还是IBM公司的名叫toad的达人解惑曰(未找到确凿证据仅仅是技术层面的推测)不实现序列化接口是因为BlazeDS在进行序列化的时候并未使用Java自己的机制如果各位有更好的解释尤其是看了BlazeDS源码的同学请过来share
BlazeDS官方文档所要求成员变量必须为public(参看_devguide/l这些白纸黑字写着Private properties constants static properties and readonly properties and so on are not serialized )?
的确声明为private的成员变量也不会出问题这个问题我想是因为官方文档滞后的原因另外就算是私有成员明显可以通过反射获取其值
接下来是接口ListDAOjava注意按照规范暴露给Flex调用的不能包含以下保留的方法名
disconnect()
getOperation()
hasOwnProperty()
initialized()
isPrototypeOf()
logout()
propertyIsEnumerable()
setCredentials()
setPropertyIsEnumerable()
setRemoteCredentials()
toString()
valueOf()
如果你不小心用到了可以参考BlazeDS官方文档RemoteObject component章节看如何解决getData()方法是供Flex端调用的传入参数是Flex构造的FlexGroup对象实例
packageorgrosenjiangflex;
importjavautilList;
/**
*DAOInterface
*@authorrosenjiang
*@since//
*
*/
publicinterfaceListDAO{
/**
*
*/
publicList<FlexGroup>getData(FlexGroupfg);
}
然后是实现类ListDAOImpljava该类利用了JdbcDaoSupport的模板方法来处理JDBC操作
packageorgrosenjiangflex;
importjavasqlResultSet;
importjavasqlSQLException;
importjavautilList;
importorgsprireJdbcTemplate;
importorgsprireRowMapper;
importorgspriresupportJdbcDaoSupport;
/**
*DAOImpl
*@authorrosenjiang
*@since//
*
*/
publicclassListDAOImplextendsJdbcDaoSupportimplementsListDAO{
/**
*
*/
publicList<FlexGroup>getData(FlexGroupfg){
//testproperties
Systemoutprintln(fggetGroupName());
Systemoutprintln(fggetMember());
Systemoutprintln(fggetMember());
Systemoutprintln(fggetMember());
Systemoutprintln(fggetMember());
Systemoutprintln(fggetMember());
//JdbcTemplate
JdbcTemplatejt=thisgetJdbcTemplate();
List<FlexGroup>list=jtquery(select*fromflex_group
newRowMapper(){
publicFlexGroupmapRow(ResultSetrsintrowNum)throwsSQLException{
FlexGroupfg=newFlexGroup();
fgsetGroupName(rsgetString(group_name));
fgsetMember(rsgetString(member));
fgsetMember(rsgetString(member));
fgsetMember(rsgetString(member));
fgsetMember(rsgetString(member));
fgsetMember(rsgetString(member));
returnfg;
}
});
returnlist;
}
}
开始写webxml文件注意由于使用了Spring BlazeDS Integration所以内容和单纯使用BlazeDS不一样以往通过messagebroker获取的请求现在交由Spring处理了
<?xmlversion=encoding=UTF?>
<webappxmlns:xsi=instancexmlns=xmlns:web=app__xsdxsi:schemaLocation=;app__xsdid=WebApp_IDversion=>
<!ThefrontcontrollerofthisSpringWebapplicationresponsibleforhandlingallapplicationrequests>
<servlet>
<servletname>SpringMVCDispatcherServlet</servletname>
<servletclass>orgspringframeworkwebservletDispatcherServlet</servletclass>
<initparam>
<paramname>contextConfigLocation</paramname>
<paramvalue>/WEBINF/classes/applicationContextxml</paramvalue>
</initparam>
<loadonstartup></loadonstartup>
</servlet>
<!Mapall/messagbrokerrequeststotheDispatcherServletforhandling>
<servletmapping>
<servletname>SpringMVCDispatcherServlet</servletname>
<urlpattern>/messagebroker/*</urlpattern>
</servletmapping>
</webapp>
最后是applicationContextxml
<?xmlversion=encoding=UTF?>
<beansxmlns=
xmlns:flex=
xmlns:xsi=instance
xsi:schemaLocation=
beansxsd
;
flexxsd>
<!DadaSource>
<beanid=dataSourceclass=monsdbcpBasicDataSourcedestroymethod=close>
<propertyname=driverClassNamevalue=netsourceforgejtdsjdbcDriver/>
<propertyname=urlvalue=jdbc:jtds:sqlserver://localhost:/cfd/>
<propertyname=usernamevalue=sa/>
<propertyname=passwordvalue=/>
</bean>
<!MessageBroker>
<flex:messagebrokerservicesconfigpath=/WEBINF/flex/servicesconfigxml/>
<!ListDataBean>
<beanid=listDAOclass=orgrosenjiangflexListDAOImpl>
<propertyname=dataSource>
<refbean=dataSource></ref>
</property>
<flex:remotingdestination/>
</bean>
</beans>
这里引入了flex命名空间拜Spring BlazeDS Integration所赐仅仅需要一个<flexremotingdestination/>节点就能让这个bean暴露给远端Flex调用另外还需要配置messagebroker来指定BlazeDS配置文件以上webxml和applicationContextxml相关配置可参考Configuring and Using the BlazeDS MessageBroker with Spring章节到此Java部分代码就完成了
Flex部分就两个文件首先是和Java相对应的FlexGroupas
package{
[Bindable]
[RemoteClass(alias=orgrosenjiangflexFlexGroup)]
publicclassFlexGroup{
publicvargroupName:String;
publicvarmember:String;
publicvarmember:String;
publicvarmember:String;
publicvarmember:String;
publicvarmember:String;
}
}
利用[RemoteClass(alias=)]元数据映射Java端的FlexGroup对象注意这里的成员名一定要一致详情可参考Explicitly mapping ActionScript and Java objects章节
最后一个是JavaFlexMappingmxml文件也就是我们的主程序界面
<?xmlversion=encoding=utf?>
<mx:Applicationxmlns:mx=backgroundColor=blackfontSize=
verticalAlign=middlehorizontalAlign=centercolor=#creationComplete=init()>
<mx:RemoteObjectid=lodestination=listDAOresult=handleResult(event)fault=handleFault(event)>
<mx:channelSet>
<mx:ChannelSet>
<mx:channels>
<mx:AMFChannel
uri=/>
</mx:channels>
</mx:ChannelSet>
</mx:channelSet>
</mx:RemoteObject>
<mx:Script>
<![CDATA[
importmxrpceventsResultEvent;
importmxrpceventsFaultEvent;
importntrolsAlert;
importllectionsArrayCollection;
varfg:FlexGroup;
varac:ArrayCollection;
privatefunctioninit():void{
//createFlexGroupinstanceforremoteDAO
fg=newFlexGroup();
fggroupName=测试组;
mber=成员;
mber=成员;
mber=成员;
mber=成员;
mber=成员;
}
privatefunctionhandleResult(event:ResultEvent):void{
ac=ArrayCollection(eventresult);
dgdataProvider=ac;
}
privatefunctionhandleFault(event:FaultEvent):void{
Alertshow(ssage出错了);
}
]]>
</mx:Script>
<mx:Panelheight=width=title=JavaFlex对象透明映射最佳实践horizontalAlign=centerverticalAlign=middle>
<mx:VBox>
<mx:ApplicationControlBardock=truewidth=>
<mx:Buttonlabel=赶快点我我就给数据click=logetData(fg)/>
</mx:ApplicationControlBar>
<mx:DataGridheight=width=id=dg>
<mx:columns>
<mx:DataGridColumnheaderText=组名dataField=groupName/>
<mx:DataGridColumnheaderText=成员一dataField=member/>
<mx:DataGridColumnheaderText=成员二dataField=member/>
<mx:DataGridColumnheaderText=成员三dataField=member/>
<mx:DataGridColumnheaderText=成员四dataField=member/>
<mx:DataGridColumnheaderText=成员五dataField=member/>
</mx:columns>
</mx:DataGrid>
</mx:VBox>
</mx:Panel>
</mx:Application>
在这里引入了RemoteObject对象并使用运行时注册机制指定AMFChannel详情可参考Accessing dynamic components with a Flex client application章节Flex程序的运行步骤是这样的当界面都创建完毕后执行init()方法构造FlexGroup对象实例并填充其成员程序进入监听状态当点击快点我我就给数据的按钮后通过RemoteObject实例调用Java端的getData()方法并传入FlexGroup对象实例供Java端测试最后由于注册了异步的handleResult()方法所以当Java端返回List对象实例后立即转换为ArrayCollection数据类型并填充到DataGrid进行显示运行截图如下
同时可以到Eclipse控制台上观察收到的数据
到此JavaFlex透明映射就完成了更多信息请参考Spring BlazeDS Integration Reference Guide以及BlazeDS Developer Guide