Flex与J2EE结合开发案例介绍

来源:岁月联盟 编辑:zhuzhu 时间:2009-05-22

     摘要:最近晚上抽出点时间写了这篇文章,关于 Flex 开发方面的语言和架构,介绍了大家都熟悉的分层结构,着重介绍视图层(flex 实现),服务控制层和领域模型层,并按照严格分层,高解耦合性并结合 Flex 技术实验了一个用户管理小模块,案例不是目的,重要的是介绍开发思想。本文第一部分介绍 Flex 相关技术以及 ActionStript3.0 语言。第二部分介绍开发实例的开发过程,代码可以下载,亮点在接口工程。由于本人 flex 经验不足,在以后的工作中会不断补充。

    关键字:Flex, J2EE, 架构

    1 Flex 介绍

    FLEX,是Rich Internet Applications时代的牛×产物Rich Internet Applications,翻译成中文为富因特网应用程序。传统网络程序的开发是基于页面的、服务器端数据传递的模式,把网络程序的表示层建立于HTML页面之上,而HTML是适合于文本的,传统的基于页面的系统已经渐渐不能满足网络浏览者的更高的、全方位的体验要求了,这就是被Macromedia公司称之为的“体验问题”,而富因特网应用程序的出现也就是为了解决这个问题。

    Flex最重要的两个技术要数AS和MXML, MXML 和 HTML 一样是标记语言,它描述了反映内容与功能的用户界面。与 HTML 不同的是,MXML 可对表示层逻辑与用户界面和服务器端数据绑定提供声明抽象。MXML 可将表示与业务逻辑的问题彻底分开,以实现最大程度地提高开发人员的生产率及应用程序的重复使用率。MXML 的开发基础是在迭代过程上,这与其他类型的 Web 应用程序文件如 HTML、JSP、ASP是相同的。开发 MXML 应用程序就象打开一个文件编辑器一样简单,只要输入一些标签、保存文件,然后在 Web 浏览器上打开文件 URL 即可。

    MXML 文件同时也是普通的 XML 文件,所以可以选择多种开发环境。可以在简单文件编辑器、专用 XML 编辑器或是支持文件编辑的集成开发环境 (IDE) 中进行开发。由于 MXML 符合 W3C XML 方案的定义,您也可以使用结构化编辑,如代码着色和代码提示。

    MXML和HTML间最大区别:前者定义的应用是编译的SWF文件,执行于FlashPlayer客户端中。后者是基于页面技术的应用。因此前者能提供更丰富的、动态的UI。MXML不支持Flash的某些特性,例如:时间轴。但是可以利用Flash设计组件并应用在Flex中。MXML应用可以是一个MXML文件,也可以是多个MXML组成,MXML支持MXML文件形式的自定义组件、ActionScript文件形式的自定义组件以及在Flash中建立的自定义组件。

    FLEX试图通过提供一个程序员们已经熟知的工作流和编程模型,让程序员比从前更快更简单地开发动画及RIA应用。在多层式开发模型中,FLEX应用属于表现层。FLEX的语言和文件结构也试图把应用程序的逻辑从设计中分离出来

    总之,flex 是未来界面开发的一个好方向,据我了解很多公司都要求员工要学习 flex 技术,可见 flex 受欢迎的程度。

    2 ActionStript3.0 特性介绍

    ActionScript 是针对 Adobe Flash Player 运行时环境的编程语言,它在 Flash 内容和应用程序中实现了交互性、数据处理以及其它许多功能,ActionScript 是由 Flash Player 中的 ActionScript 虚拟机 (AVM) 来执行的。ActionScript代码通常被编译器编译成“字节码格式” ,有点类似 java 的处理和运行机制。变过 C#,Java和javascript程序的朋友,肯定能在 ActionScript 中找到这些语言的影子。

    2.1 内置命名空间和自定义命名空间

    四个内置修饰符:

     1public :对所有代码可见
    2
    3private: 只对类内部可见
    4
    5internal :只对定义所在的同一包内可见
    6
    7protected :对同一包以及不同包的子类可见
    8


    自定义命名空间:使用关键字namespace定义命名空间,声明属性和方法时,应用命名空间。

    AS 代码:

    1Namespace testSpace="org.blogjava.jm/ testSpace ";
    2
    3testSpace myfunction2():void{}
    4
    5 调用使用 use 关键字打开命名空间
    6
    7use mySpace2;
    8
    9myfunction2();


    2.2 Local 变量特点

    与java不同的是,在as3中,变量没有块级作用域(即两人大括号中间),如果在一个块内声明了一个变量,比如一个for循环内声明了一个变量,它在该代码所在整个函数内都是可访问的。

    1function myFunction():void{
    2
    3 for(var i:int=0;i<5:i++){
    4
    5 var last:int = i;
    6
    7 }
    8
    9 trace(last);
    10
    11}
    12


    last 在 for 中定义但可以在 for 块外面访问到,个人觉得这样设计欠妥,尽管很方便。

    2.3 Dynamic 类

    Object 类本身就是动态类,当然也可以用 dynamic 关键字来声明一个类,所谓动态就是在运行时可以对类追加属性和方法。

    1dynamic class Protean{}
    2
    3 var myProtean:Protean = new Protean();
    4
    5myProtean.name = "jack.wang";
    6
    7myProtean.password = 3;
    8
    9trace(myProtean. name , myProtean. password );
    10
    2.4 定义函数的两种方式:函数语句和函数表达式

     1 //函数语句声明
    2
    3Function fun1():void{}
    4
    5 //函数表达式声明
    6
    7var fun2:Function = function():void{}
    8
    9函数表达式声明的函数是不能够被垃圾回收的,必须显示的调用 delete 命令。
    10
    11var t:Test = new Test(); //t是动态类Test的一个实例
    12
    13t.funt = function(){};//把一个函数声明为t的一个属性
    14
    15delete t.funt; //删除刚才新增的函数,我们刚才声明的函数也被回收了
    16

     2.5 在as3中也有arguments对象,功能基本上和javascript中的一样。

    arguments 对象是一个数组,其中包括传递给函数的所有参数,arguments.length 属性报告传递给函数的参数数量,(避免将 "arguments" 字符串作为参数名,因为它将遮蔽 arguments 对象)

     1 function traceArgArray(x:int):void
    2
    3{
    4
    5 for (var i:uint = 0; i < arguments.length; i++)
    6
    7 {
    8
    9 trace(arguments[i]);
    10
    11 }
    12
    13}
    14
    15traceArgArray(1, 2, 3);
    16
    17// 输出:
    18
    19// 1
    20
    21// 2
    22
    23// 3
    24

    当然也可以用类似 java 的形式

    function traceArgArray(x: int, args)

    2.6 在as3中允许定义同名的静态属性和实例属性
    1class StaticTest
    2
    3{
    4
    5 static var message:String = "static variable";
    6
    7 var message:String = "instance variable";
    8
    9}
    10
    11// 在脚本中
    12
    13var myST:StaticTest = new StaticTest();
    14
    15trace(StaticTest.message); // 输出:静态变量
    16
    17trace(myST.message); // 输出:实例变量
    18


    2.7 在as中有一个叫做set和get存取器的东西,类似JavaBean,但又有所不同。

    class GetSe
    t{

    private var privateProperty:String;

    public function get publicAccess():String

    {

    return privateProperty;

    }

    public function set publicAccess(setValue:String):void

    {
    privateProperty = setValue;
    }
    }

   3 案例介绍

    案例是超级简单的,开发Web 应用的,不管你是基于 J2EE,.net 平台还是其他的 PHP 等等都很熟悉分层架构,其中五层是最熟悉不过的了,一般分为表示层,控制层,服务层,模型层和数据层,有的公司干脆就把服务层和模型层合并起来和控制层合并在一起,基于分层的开发可以横向也可以纵向,由于引入 flex 技术,因为并不是所有人都懂得 flex 开发方式,尽管他和传统的 Swing, SWT,GWT开发很相近 ,不过这样需求分析时可以构建可演进的原型系统,界面也很 RIA。

    人们常提面向接口编程于是经常看到 IUser user=new User();这样的代码,似乎就是在用接口,但是 new 的动作还是有依赖,于是人们用一些设计模式比如 Factory, Proxy,反射等等模式,后来又有了更好的依赖注入,似乎很完美了,可人们又陷进了过度设计,其实接口应用比直接用原类要多耗费几个机械指令 User user=new User(),而且在一个内聚的组件中尽量用对象直接连接,该分开的时候我们去用接口分,接口的目的是为了抽象,抽象的目的是为了解耦。

    本开发为了把模型层和服务层完全分开,引入接口工程,也就是单独开发一个工程来设计接口,这个工程有设计师开发。

    用户接口:

    package org.blogjava.model;

    /** *//**

   

    *

    */

    publicinterface IUser {

    long getId();

    void setId(long id);

    void setUserName(String name);

    String getUserName();

    void setPassword(String password);

    String getPassword();

    void setEmail(String email);

    String getEmail();

    void setAddress(String address);

    String getAddress();

    }


    工厂接口:

    package org.blogjava.dao;

    import java.util.List;

    import org.blogjava.model.IUser;

    import org.blogjava.util.InstanceUtils;

    import org.blogjava.util.PropertiesUtils;

    /** *//**

   

    *

    */

    publicinterface DAOFactory {

    publicfinal String IMPL_NAME = PropertiesUtils.getParam(

    "/DaoFactoryImpl.properties", "DAOFactoryImpl");

    publicfinal DAOFactory factory = (DAOFactory) InstanceUtils

    .newInstance(IMPL_NAME);

    boolean checkUserValid(String userName, String password);

    IUser getUserById(String id);

    IUser createUser(IUser user);

    boolean deleteUserById(String id);

    boolean updateUser(IUser user);

    List<IUser> getAllUsers();

    }
    这两个类在单独的工程里开发,以便于模型和服务层同步开发。

    在服务层不能对外暴露 IUser 接口,而他也要接受数据,这里用的是 UserVO 对象来封装数据,服务层不操作模型层的任何实现类,这样这两层之间完全解耦。

    package org.blogjava.vo;

    /** *//**

   

    *

    */

    publicclass UserVO {

    publiclongid;

    public String userName;

    public String password;

    public String email;

    public String address;

    public UserVO() {

    }

    }

    Flex 开发和 HTML开发有很大的不同,客户端和服务端交互的不是 HTML 而是 XML,所以在服务器端的 Servlet 就应该输出 XML 流到客户端

    判断登录:

    public ActionForward execute(ActionMapping mapping, ActionForm form,

    HttpServletRequest request, HttpServletResponse response) {

    String userName = request.getParameter("userName");

    String password = request.getParameter("password");

    String sucess = "<?xml version=""1.0"" encoding=""utf-8""?><result><msg>sucess</msg></result>";

    String unsucess = "<?xml version=""1.0"" encoding=""utf-8""?><result><msg>unsucess</msg></result>";

    response.setContentType("text/xml");

    try {

    if (userName == null || "".equals(userName)) {

    response.getOutputStream().write(unsucess.getBytes());

    returnnull;

    }

    if (password == null || "".equals(password)) {

    response.getOutputStream().write(unsucess.getBytes());

    returnnull;

    }

    IUserService service = new IUserServiceImpl();

    if (service.isUserValid(userName, password)) {

    response.getOutputStream().write(sucess.getBytes());

    } else {

    response.getOutputStream().write(unsucess.getBytes());

    }

    } catch (IOException e) {

    e.printStackTrace();

    }

    returnnull;

    }


    得到所有的用户:

    public ActionForward execute(ActionMapping mapping, ActionForm form,

    HttpServletRequest request, HttpServletResponse response) {

    IUserService service = new IUserServiceImpl();

    List<UserVO> users = service.getAllUsers();

    try {

    StringBuffer returnStr = new StringBuffer(

    "<?xml version=""1.0"" encoding=""utf-8""?>");

    returnStr.append("<users>");

    for (UserVO user : users) {

    returnStr.append("<user>");

    returnStr.append("<id>" + user.id + "</id>");

    returnStr.append("<userName>" + user.userName + "</userName>");

    returnStr.append("<password>" + user.password + "</password>");

    returnStr.append("<email>" + user.email + "</email>");

    returnStr.append("<address>" + user.address + "</address>");

    returnStr.append("</user>");

    }

    returnStr.append("</users>");

    response.getOutputStream().write(returnStr.toString().getBytes());

    System.out.println(returnStr.toString());

    } catch (IOException e) {

    e.printStackTrace();

    }

    returnnull;

    }


    最后 Flex 也是一个单独的工程,通过 HTTPService 和 Web 服务器端交互数据
    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="" layout="absolute" backgroundGradientAlphas="[0.72, 1.0]" backgroundGradientColors="[#FFFFFF, #FFFFFF]">

    <mx:HTTPService
    showBusyCursor="true"
    id="loginSrv"
    result="doResult();"
    method="GET"
    url="">
    <mx:request>
    <userName>
    {txtname.text}
    </userName>
    <password>
    {txtpwd.text}
    </password>
    </mx:request>
    </mx:HTTPService>
    <mx:HTTPService
    showBusyCursor="true"
    id="loadUsers"
    method="GET" result="users = event.result.users.user"
    url="">
    </mx:HTTPService>
    <mx:Script>
    <![CDATA[
    import mx.controls.Alert;
    import mx.utils.ObjectUtil;
    import mx.collections.ArrayCollection;

    [Bindable]
    var users:ArrayCollection=new ArrayCollection();
    internal function doResult():void
    {
    var returnValue:String=loginSrv.lastResult.result.msg;
    if(returnValue=="sucess")
    {
    login.visible=false;
    loadUsers.send();
    userList.visible=true;
    }
    else
    {
    Alert.show("登录失败","提示信息",Alert.OK,this,null,null,Alert.YES);
    }
    }
    private function index_sortCompareFunc(itemA:Object, itemB:Object):int {
    // Make sure itemA has an "index" property.
    if (!itemA.hasOwnProperty("id")) {
    itemA.index = null;
    }
    // Make sure itemB has an "index" property.
    if (!itemB.hasOwnProperty("id")) {
    itemB.index = null;
    }
    // Perform a numeric sort.
    return ObjectUtil.numericCompare(itemA.index, itemB.index);
    }
    ]]>
    </mx:Script>
    <mx:Panel id="login" x="285.5" y="127" width="341" height="238" layout="absolute" fontFamily="Arial" fontSize="13" color="#3C280B" borderStyle="none" borderColor="#CC0B0B" cornerRadius="10" alpha="0.64">
    <mx:TextInput id="txtname" x="101" y="34" width="172" displayAsPassword="true" editable="true" enabled="true"/>
    <mx:Button x="92" y="130" label="登录" labelPlacement="top" enabled="true" click="loginSrv.send();"/>
    <mx:Button x="183" y="130" label="取消"/>
    <mx:TextInput id="txtpwd" x="101" y="75" width="172" displayAsPassword="true" editable="true" enabled="true"/>
    <mx:Label x="44" y="36" text="帐号:" width="49" height="20" enabled="true"/>
    <mx:Label x="44" y="77" text="密码:" width="49" height="20" enabled="true"/>
    </mx:Panel>
    <mx:Panel id="userList" x="181.5" y="98" width="576" height="311" layout="absolute" visible="false">
    <mx:DataGrid x="0" y="0" width="556" height="271" sortableColumns="true" dataProvider="{users}" editable="true" enabled="true">
    <mx:columns>
    <mx:DataGridColumn headerText="编号" dataField="id" />
    <mx:DataGridColumn headerText="姓名" dataField="userName" />
    <mx:DataGridColumn headerText="密码" dataField="password"/>
    <mx:DataGridColumn headerText="邮件" dataField="email"/>
    <mx:DataGridColumn headerText="地址" dataField="address"/>
    </mx:columns>
    </mx:DataGrid>
    </mx:Panel>
    </mx:Application>


    4 小结

    在写这篇文章的时候已经是深夜了,可能有很多地方表述有问题,也可能有的思想没有表述清楚,欢迎大家讨论,就先写到这里,有时间我会继续补上一些内容。