Java Flex对象透明映射最佳实践

Java Flex对象透明映射最佳实践

在我之前的两篇文章Flex3 性能提示 、Ajax轮询以及Comet模式—写在Servlet 3.0发布之前中。我反复提到Adobe BlazeDS这个开源产品,假设某天,你在看了Flex3 性能提示之后放弃了Flex+Servlet+XML方案,那么如何进行下一步?本文试图用简单的表述来实践一回JavaFlex之间的对象透明传递,所谓透明本人理解为不需要人工的(反)序列化。在阅读本文之前,你需要有一定的SpringBlazeDSFlex使用经验。

我使用的是Eclipse 3.4 Java EE平台和Tomcat6.x以及SQL Server 2005,为了不脱俗,选用了Spring(传说中的春天框架)外加最近才GASpring BlazeDS IntegrationPS:其实不用春天框架也可以,只是觉得他的JdbcDaoSupport很不错,可以自己偷懒了,而且连接池和JDBC驱动这些基础设施也all-in-one了。另外,要使用Spring BlazeDS Integration需满足它3个愿望:Java 5 or higherSpring 2.5.6 or higherAdobe BlazeDS 3.2 or higher(推荐下载blazeds-turnkey),我想这三个愿望在google上是很好实现的。成品的项目结构是这样的,对于如此简单的实践,无需用到Service层:

                   

有了上面的目标,接下来就很好办了。首先创建名为“JavaFlexMapping”的动态Web项目,接着导入“blazeds-turnkey-3.2.x.xxxx\resources\lib”下的所有jar;至于Spring相关的jar,你可以根据自己的经验导入,也可以先导入spring.jar然后导入spring-webmvc.jar(Spring BlazeDS Integration需要),最后再把“spring-framework-2.5.6\lib”下的所有jar都导入进来,这样干牺牲了磁盘空间,但换来了更少的烦恼;Spring BlazeDS Integration的org.springframework.flex-1.0.0.RELEASE.jar也导入进来吧。这就算完成了部分包导入工作,不过在实际使用中,还会需要其他jar:xalan.jar、backport-util-concurrent.jar、jtds-1.2.2.jar(SQL Server JDBC驱动),如果在之后的实际操作中出现缺包情况,Spring会在控制台说明的。最后把blazeds-turnkey-3.2.x.xxxx 下的“\tomcat\webapps\blazeds\WEB-INF\flex”文件全部拷贝到WEB-INF下的flex目录中。

Java程序的运行环境都配置好了,看看表结构是怎样的:

                   

这是一个简单的表,反映了组和五个组成员的信息。

所有必要的资源准备完毕,可以编码了,先看VO类“FlexGroup.java”的内容:

package  org.rosenjiang.flex;

/**
 *  Flex Group Object
 *  
@author   rosen jiang
 *  
@since   2009/06/21
 * 
 
*/
public   class  FlexGroup {

    
private  String groupName;
    
private  String member1;
    
private  String member2;
    
private  String member3;
    
private  String member4;
    
private  String member5;
    
    
public  String getGroupName() {
        
return  groupName;
    }
    
public   void  setGroupName(String groupName) {
        
this .groupName  =  groupName;
    }
    
public  String getMember1() {
        
return  member1;
    }
    
public   void  setMember1(String member1) {
        
this .member1  =  member1;
    }
    
public  String getMember2() {
        
return  member2;
    }
    
public   void  setMember2(String member2) {
        
this .member2  =  member2;
    }
    
public  String getMember3() {
        
return  member3;
    }
    
public   void  setMember3(String member3) {
        
this .member3  =  member3;
    }
    
public  String getMember4() {
        
return  member4;
    }
    
public   void  setMember4(String member4) {
        
this .member4  =  member4;
    }
    
public  String getMember5() {
        
return  member5;
    }
    
public   void  setMember5(String member5) {
        
this .member5  =  member5;
    }
}

没啥好说的,就是一个表结构的对象化表述,不过有两个问题。

1、既然牵涉到跨语言的对象传输为什么没实现序列化接口?

为了让自己和大家了解,昨天我专门请教了据说是Sun公司还是IBM公司的名叫toad的达人,解惑曰(未找到确凿证据,仅仅是技术层面的推测):不实现序列化接口是因为BlazeDS在进行序列化的时候并未使用Java自己的机制。如果各位有更好的解释,尤其是看了BlazeDS源码的同学请过来share。

2、BlazeDS官方文档所要求成员变量必须为public(参看http://livedocs.adobe.com/blazeds/1/blazeds_devguide/serialize_data_3.html,这些白纸黑字写着:”Private properties, constants, static properties, and read-only properties, and so on, are not serialized. “)?

的确,声明为private的成员变量也不会出问题,这个问题我想是因为官方文档滞后的原因,另外就算是私有成员明显可以通过反射获取其值。

接下来是接口“ListDAO.java”,注意,按照规范,暴露给Flex调用的不能包含以下保留的方法名:

disconnect()

getOperation()

hasOwnProperty()

initialized()

isPrototypeOf()

logout()

propertyIsEnumerable()

setCredentials()

setPropertyIsEnumerable()

setRemoteCredentials()

toString()

valueOf()

如果你不小心用到了,可以参考BlazeDS官方文档“RemoteObject component”章节,看如何解决。getData()方法是供Flex端调用的,传入参数是Flex构造的FlexGroup对象实例:

package  org.rosenjiang.flex;

import  java.util.List;


/**
 *  DAO Interface
 *  
@author   rosen jiang
 *  
@since   2009/06/21
 * 
 
*/
public   interface  ListDAO {

    
/**
     * .
     
*/
    
public  List < FlexGroup >  getData(FlexGroup fg);
}

然后是实现类“ListDAOImpl.java”,该类利用了JdbcDaoSupport的模板方法来处理JDBC操作:

package  org.rosenjiang.flex;

import  java.sql.ResultSet;
import  java.sql.SQLException;
import  java.util.List;

import  org.springframework.jdbc.core.JdbcTemplate;
import  org.springframework.jdbc.core.RowMapper;
import  org.springframework.jdbc.core.support.JdbcDaoSupport;

/**
 *  DAO Impl
 *  
@author   rosen jiang
 *  
@since   2009/06/21
 * 
 
*/
public   class  ListDAOImpl  extends  JdbcDaoSupport  implements  ListDAO {

    
/**
     * .
     
*/
    
public  List < FlexGroup >  getData(FlexGroup fg){
        
// test properties
        System.out.println(fg.getGroupName());
        System.out.println(fg.getMember1());
        System.out.println(fg.getMember2());
        System.out.println(fg.getMember3());
        System.out.println(fg.getMember4());
        System.out.println(fg.getMember5());
        
// Jdbc Template
        JdbcTemplate jt  =   this .getJdbcTemplate();
        List
< FlexGroup >  list  =  jt.query( " select * from flex_group "
                
new  RowMapper() {
            
public  FlexGroup mapRow(ResultSet rs,  int  rowNum)  throws  SQLException {
                FlexGroup fg 
=   new  FlexGroup();
                fg.setGroupName(rs.getString(
" group_name " ));
                fg.setMember1(rs.getString(
" member1 " ));
                fg.setMember2(rs.getString(
" member2 " ));
                fg.setMember3(rs.getString(
" member3 " ));
                fg.setMember4(rs.getString(
" member4 " ));
                fg.setMember5(rs.getString(
" member5 " ));
            
return  fg;
            }
            });
        
return  list;
    }
}

开始写“web.xml”文件,注意,由于使用了Spring BlazeDS Integration,所以内容和单纯使用BlazeDS不一样,以往通过messagebroker获取的请求,现在交由Spring处理了:

<? xml version="1.0" encoding="UTF-8" ?>
< web-app  xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"  xmlns ="http://java.sun.com/xml/ns/javaee"  xmlns:web ="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"  xsi:schemaLocation ="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"  id ="WebApp_ID"  version ="2.5" >

    
<!--  The front controller of this Spring Web application, responsible for handling all application requests  -->
    
< servlet >
        
< servlet-name > Spring MVC Dispatcher Servlet </ servlet-name >
        
< servlet-class > org.springframework.web.servlet.DispatcherServlet </ servlet-class >
        
< init-param >
            
< param-name > contextConfigLocation </ param-name >
            
< param-value > /WEB-INF/classes/applicationContext.xml </ param-value >
        
</ init-param >
        
< load-on-startup > 1 </ load-on-startup >
    
</ servlet >
    
<!--  Map all /messagbroker requests to the DispatcherServlet for handling  -->
    
< servlet-mapping >
        
< servlet-name > Spring MVC Dispatcher Servlet </ servlet-name >
        
< url-pattern > /messagebroker/* </ url-pattern >
    
</ servlet-mapping >    
</ web-app >

最后是“applicationContext.xml”:

<? xml version="1.0" encoding="UTF-8" ?>
< beans  xmlns ="http://www.springframework.org/schema/beans"
       xmlns:flex
="http://www.springframework.org/schema/flex"
       xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation
="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/flex 
           http://www.springframework.org/schema/flex/spring-flex-1.0.xsd"
>

<!--  Dada Source  -->
    
< bean  id ="dataSource"  class ="org.apache.commons.dbcp.BasicDataSource"  destroy-method ="close" >
        
< property  name ="driverClassName"  value ="net.sourceforge.jtds.jdbc.Driver" />
        
< property  name ="url"  value ="jdbc:jtds:sqlserver://localhost:1433/cfd" />
        
< property  name ="username"  value ="sa" />
        
< property  name ="password"  value ="123456" />
    
</ bean >
    
<!--  Message Broker  -->
< flex:message-broker  services-config-path ="/WEB-INF/flex/services-config.xml" />
    
<!--  List Data Bean  -->
    
< bean  id ="listDAO"  class ="org.rosenjiang.flex.ListDAOImpl" >
      
< property  name ="dataSource" >
        
< ref  bean ="dataSource" ></ ref >
      
</ property >
      
< flex:remoting-destination />
    
</ bean >
</ beans >

这里引入了flex命名空间,拜Spring BlazeDS Integration所赐,仅仅需要一个“<flex:remoting-destination/>”节点,就能让这个“bean”暴露给远端Flex调用。另外还需要配置“message-broker”,来指定BlazeDS配置文件。以上“web.xml”和“applicationContext.xml”相关配置可参考“Configuring and Using the BlazeDS MessageBroker with Spring”章节,到此,Java部分代码就完成了。

Flex部分就两个文件,首先是和Java相对应的“FlexGroup.as”:

package{
    [Bindable]
    [RemoteClass(alias
= " org.rosenjiang.flex.FlexGroup " )]
    public class FlexGroup{
        public 
var  groupName:String;
        public 
var  member1:String;
        public 
var  member2:String;
        public 
var  member3:String;
        public 
var  member4:String;
        public 
var  member5:String;
    }
}

利用[RemoteClass(alias="")]元数据映射Java端的FlexGroup对象,注意这里的成员名一定要一致,详情可参考“Explicitly mapping ActionScript and Java objects”章节。

最后一个是“JavaFlexMapping.mxml”文件,也就是我们的主程序界面:

<? xml version="1.0" encoding="utf-8" ?>
< mx:Application  xmlns:mx ="http://www.adobe.com/2006/mxml"  backgroundColor ="black"  fontSize ="12"
     verticalAlign
="middle"  horizontalAlign ="center"  color ="#000506"  creationComplete ="init()" >
    
    
< mx:RemoteObject  id ="lo"  destination ="listDAO"  result ="handleResult(event)"  fault ="handleFault(event)" >
        
< mx:channelSet >
            
< mx:ChannelSet >
                
< mx:channels >
                    
< mx:AMFChannel
                        
uri ="http://127.0.0.1:8080/JavaFlexMapping/messagebroker/amf" />
                
</ mx:channels >
            
</ mx:ChannelSet >
        
</ mx:channelSet >
    
</ mx:RemoteObject >

    
< mx:Script >
        
<![CDATA[
            import mx.rpc.events.ResultEvent;
            import mx.rpc.events.FaultEvent;
            import mx.controls.Alert;
            import mx.collections.ArrayCollection;
            var fg:FlexGroup;
            var ac:ArrayCollection;

            private function init():void{
                //create FlexGroup instance for remote DAO
                fg = new FlexGroup();
                fg.groupName = "测试组";
                fg.member1 = "成员1";
                fg.member2 = "成员2";
                fg.member3 = "成员3";
                fg.member4 = "成员4";
                fg.member5 = "成员5";
            }

            private function handleResult(event:ResultEvent):void{
                ac = ArrayCollection(event.result);
                dg.dataProvider = ac;
            }

            private function handleFault(event:FaultEvent):void{
                Alert.show(event.fault.message, "出错了");
            }
        
]]>
    
</ mx:Script >
    
< mx:Panel  height ="364"  width ="592"  title ="Java Flex对象透明映射最佳实践"  horizontalAlign ="center"  verticalAlign ="middle" >
        
< mx:VBox >
            
< mx:ApplicationControlBar  dock ="true"  width ="551" >
                
< mx:Button  label ="赶快点我 我就给数据"  click ="lo.getData(fg)" />
            
</ mx:ApplicationControlBar >

            
< mx:DataGrid  height ="255"  width ="551"  id ="dg" >
                
< mx:columns >
                    
< mx:DataGridColumn  headerText ="组名"  dataField ="groupName" />
                    
< mx:DataGridColumn  headerText ="成员一"  dataField ="member1" />
                    
< mx:DataGridColumn  headerText ="成员二"  dataField ="member2" />
                    
< mx:DataGridColumn  headerText ="成员三"  dataField ="member3" />
                    
< mx:DataGridColumn  headerText ="成员四"  dataField ="member4" />
                    
< mx:DataGridColumn  headerText ="成员五"  dataField ="member5" />
                
</ 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控制台上观察收到的数据。

到此,Java、Flex透明映射就完成了,更多信息请参考“Spring BlazeDS Integration Reference Guide”以及“BlazeDS Developer Guide”。


 

 

请注意!引用、转贴本文应注明原作者:Rosen Jiang 以及出处: http://www.blogjava.net/rosen

 

你可能感兴趣的:(Java Flex对象透明映射最佳实践)