Cairngorm+BlazeDS整合Flex+Java的Demo(实例)

来源:互联网 发布:5元已备案域名 编辑:程序博客网 时间:2024/06/05 10:55

今天学习Cairngorm,找了份教程,写了个Demo,以记录并分享学习过程。

Cairngorm的各个部分:

  1. ModelLocator:在一个地方存储程序中所有的值对象(ValueObjects,数据)并共享变量。它与HTTP Session对象相类似,不过它存储在Flex客户端,而不是存储在一个中间层程序服务器的服务器端。
  2. View(视图):一个或多个Flex组件(Button,panel,combo Box,Tile等等)绑定到一起形成的一个特定的个体,使用ModelLocator中的数据并且针对用户的交互动作(如点击,鼠标滑过,拖拽等)产生自定义的CairngormEvents。
  3. FrontController(前端控制器):接受CairngormEvents并且将它们映射到CairngormCommands。
  4. Command(命令):处理业务逻辑,调用CairngormDelegates或其他的Commands,以及更新ModelLocator中存储的值对象和变量。
  5. Delegate(委托):由一个Command创建,它将远程过程实例化并且将结果返回给Command。
  6. Service(服务):定义链接到远程数据库的远程过程调用(HTTP,Web Services等)。

Cairngorm的工作流程大体是这样:

客户端界面由View组成的。View使用Flex的binding(绑定)来显示ModelLocator中包含的数据。View根据诸如鼠标点击,按钮按下以及拖拽之类的用户动作产生Event。这些Event被FrontController“广播”并“监听”,FrontController会将Event映射到Command。Command包括业务逻辑,创建所需的Delegate,处理Delegate的响应,以及更新存储在ModelLocator中的数据。由于View是绑定到ModelLocator中的数据上的,所以当ModelLocator中的数据改变的时候View也会自动更新。Delegate调用Service并且将结果提交给Command,这一步是可选的,但是推荐这么做。Service调用远程数据然后将结果提交给Delegate。

Delegate的最简单的形式就是一个中间人的角色。如果一个Command需要调用webservice来获得一些数据,它将创建一个Delegate来完成这个调用。一个Command创建一个Delegate,Delegate调用一个指定的dataService,Service返回结果给Delegate,Delegate返回结果给Command。

Delegate并不是100%必需的,但是当涉及测试&程序环境的时候它们很有帮助。相对于在Command代码中使用查找替换改变所有的引用来测试,将一个Delegate重映射到一个测试Service更为简单。

下面说我的Demo:完成用户登录在后台进行验证合法性,并反馈给前台。

工具及环境介绍:详见我的上篇文章,BlazeDS实现Flex和Java通信的Demo

版本说明:

Flex:Flex 4;

ActionScript:ActionScript 3;

Java JDK:jdk1.6.0_20

Cairngorm,我用的是版本2.2,好像Cairngorm 3已经发布了,但是官网没提供下载。下载cairngorm2_2_1-bin.zip,我们要用的已经打包好的资源文件Cairngorm.swc,将其拷贝到Flex工程的libs目录下面即可。

  1. 后台Java服务端项目CairngormDemo工程组成:


  2. 相应代码:
    UserVO.java

    package net.dreamhui.java;public class UserVO {public String userName;public String passWord;   //和ActionScript对应得构造方法public UserVO(){}//getters & setterspublic String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassWord() {return passWord;}public void setPassWord(String passWord) {this.passWord = passWord;}}


    LoginUser.java

    package net.dreamhui.java;public class LoginUser {public UserVO currentUser;private String uName;private String pWord;//Flex端要调用的服务public UserVO login(UserVO par_user){//UserVO par_user2 = UserVO(par_user);uName = par_user.userName;pWord = par_user.passWord;if(uName.equalsIgnoreCase("wwh")&&pWord.equalsIgnoreCase("wwh")){return par_user;//return "欢迎用户:"+uName;}else{return null;//return "用户名或密码错误,请重新输入";}}}

    配置文件(要添加的内容):
    remoting-config.xml

    <destination id="loginUser"><properties><source>net.dreamhui.java.LoginUser</source></properties></destination>

  3. 前台Flex工程CairngormDemo工程组成:


  4. 按照 ValueObjects模型(UserVO.as)——>模型定位(UserModelLocator.as)——>视图(loginView.mxml及主应用视图CairngormDemo.mxml)——>事件(LoginEvent.as)——>前端控制器(LoginController.as)——>Command(LoginCommand.as)——>委派代理(LoginDelegate.as)——>服务定位(LoginServiceLocator.mxml)依次的相应代码如下(因为文件中注释较多,不多写注解):
    UserVO.as

    package net.dreamhui.vo{/** * 我看的教程里面讲绑定ValueObject到远程Java类的方法是这样的, * public static var registered:Boolean = this.registerClass(); * 可能又是版本问题,在我这儿是通不过的,我到网上找到了如下的解决方法: * [RemoteClass(alias="net.dreamhui.java.UserVO")], * 估计是我看的教程版本太低了,呵呵 * */import com.adobe.cairngorm.vo.ValueObject;[Bindable][RemoteClass(alias="net.dreamhui.java.UserVO")]public class UserVO implements ValueObject{private var _userName:String;private var _passWord:String;/** * 为了实现远程Class之间的绑定,构造方法必须形式上完全一致, * 包括参数的个数和类型,否则会出现异常。 * */public function UserVO(){}//getters & setterspublic function get userName():String{return _userName;}public function set userName(value:String):void{_userName = value;}public function get passWord():String{return _passWord;}public function set passWord(value:String):void{_passWord = value;}}}

    UserModelLocator.as

    package net.dreamhui.model{import com.adobe.cairngorm.CairngormError;import com.adobe.cairngorm.CairngormMessageCodes;import com.adobe.cairngorm.model.ModelLocator;import flash.events.Event;import net.dreamhui.vo.UserVO;//绑定全局View数据[Bindable]public class UserModelLocator implements ModelLocator{private var _currentUser:UserVO;public static const LOGIN_YES:String = "loginYes";private static var instance:UserModelLocator;//单例模式public function UserModelLocator(){if(instance == !null){throw new CairngormError(CairngormMessageCodes.SINGLETON_EXCEPTION,"UserModelLocator");}instance = this;}public static function getInstance():UserModelLocator{if(instance == null){instance = new UserModelLocator();}return instance;}public function get currentUser():UserVO{return _currentUser;}/** * 此赋值操作绑定loginYes事件,当输入数据合法时候,将改变当前的登录状态 * **/[Bindable("loginYes")]public function set currentUser(value:UserVO):void{_currentUser = value;dispatchEvent(new Event(UserModelLocator.LOGIN_YES));}}}


    loginView.mxml

    <?xml version="1.0" encoding="utf-8"?><s:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"xmlns:s="library://ns.adobe.com/flex/spark"xmlns:mx="library://ns.adobe.com/flex/mx"title="请登陆" currentState="initState"creationComplete="lvcreationComplete(event)"><!--~~~~~~~~~~~~~~~~~~~~~~Script~~~~~~~~~~~~~~~~~~~~~~--><fx:Script><![CDATA[import mx.controls.Alert;import mx.events.FlexEvent;import mx.rpc.events.FaultEvent;import mx.rpc.events.ResultEvent;import mx.validators.Validator;import mx.events.ValidationResultEvent;import mx.core.UIComponent;import net.dreamhui.control.LoginEvent;import net.dreamhui.model.UserModelLocator;import net.dreamhui.vo.UserVO;/***************************************************/private var validObjs:Array;/***************************************************/protected function lvcreationComplete(event:FlexEvent):void{validObjs = [unSV,pwSV];}protected function submit(event:MouseEvent):void{var validatorResults:Array;validatorResults = Validator.validateAll(validObjs);if(validatorResults.length == 0){var user:UserVO = new UserVO();user.userName = uName.text;user.passWord = pWord.text;var lgEvent:LoginEvent = new LoginEvent(LoginEvent.LOGIN_USER);lgEvent.data = user;lgEvent.dispatch();//派发事件/***LoginEvent继承自com.adobe.cairngorm.control.CairngormEvent,* 用父类的方法dispatch派发事件;* 其实CairngormEvent继承自flash.events.Event* dispatch是CairngormEventDispatcher类封装IEventDispatcher* 的dispatchEvent()方法* **/}else{//定义校验出错事件var vEvent:ValidationResultEvent;//取出第一个出错事件vEvent = validatorResults[0] as ValidationResultEvent;//将光标定位到第一个出错的组件上(vEvent.target.source as UIComponent).setFocus();}}]]></fx:Script><!--~~~~~~~~~~~~~~~~~~~~~~states~~~~~~~~~~~~~~~~~~~~~~--><s:states><s:State name="initState"/><s:State name="loginState"/></s:states><!--~~~~~~~~~~~~~~~~~~~~~~Declarations~~~~~~~~~~~~~~~~~~~~~~--><fx:Declarations><!--定义用户名和密码的输入校验类--><mx:StringValidator id="unSV"source="{uName}"property="text"required="true"maxLength="10"tooLongError="用户名最长为10位"requiredFieldError="请填写用户名" /><mx:StringValidator id="pwSV"source="{pWord}"property="text"required="true"maxLength="10"tooLongError="密码最长为10位"requiredFieldError="请填写密码" /></fx:Declarations><!--~~~~~~~~~~~~~~~~~~~~~~UI Components~~~~~~~~~~~~~~~~~~~~~~--><mx:Form includeIn="initState"><mx:FormItem label="用户名" ><s:TextInput id="uName" /></mx:FormItem><mx:FormItem label="密 码" ><s:TextInput id="pWord" displayAsPassword="true" /></mx:FormItem><mx:FormItem><s:Button id="submitBtn" click="submit(event)"  label="登陆" right="0" /></mx:FormItem></mx:Form><s:HGroup includeIn="loginState" top="20" left="10" ><s:Label  text="欢迎尊贵的用户:"/><s:Label  id="cuName" text="{UserModelLocator.getInstance().currentUser.userName}" /></s:HGroup></s:Panel>


    CairngormDemo.mxml

    <?xml version="1.0" encoding="utf-8"?><s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"xmlns:s="library://ns.adobe.com/flex/spark"xmlns:mx="library://ns.adobe.com/flex/mx"xmlns:business="net.dreamhui.business.*"xmlns:control="net.dreamhui.control.*"xmlns:view="net.dreamhui.view.*"creationComplete="creationComplete()"><!--~~~~~~~~~~~~~~~~~~~~~~Script~~~~~~~~~~~~~~~~~~~~~~--><fx:Script><![CDATA[import mx.controls.Alert;import mx.events.FlexEvent;import net.dreamhui.model.UserModelLocator;/***************************************************/protected function creationComplete():void{UserModelLocator.getInstance().addEventListener(UserModelLocator.LOGIN_YES,switchState);}protected function switchState(event:Event):void{lgView.currentState = "loginState";}]]></fx:Script><!--~~~~~~~~~~~~~~~~~~~~~~Declarations~~~~~~~~~~~~~~~~~~~~~~--><fx:Declarations><!--初始化服务,里面含有Command注册 和 远程过程调用的信息--><business:LoginServiceLocator id="lgService" /><control:LoginController id="loginContr" /><!--<commands:LoginCommand id="lCommand" />--><!--<model:UserModelLocator id="uLocator" />--></fx:Declarations><!--~~~~~~~~~~~~~~~~~~~~~~UI Components~~~~~~~~~~~~~~~~~~~~~~--><view:loginView id="lgView" top="10" horizontalCenter="0" width="30%"height="30%" fontSize="20"/></s:Application>


    LoginEvent.as

    package net.dreamhui.control{import com.adobe.cairngorm.control.CairngormEvent;import net.dreamhui.vo.UserVO;public class LoginEvent extends CairngormEvent{//定义事件类型常量public static const LOGIN_USER:String = "loginUser";public function LoginEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false){super(type, bubbles, cancelable);}}}


    LoginController.as

    package net.dreamhui.control{import com.adobe.cairngorm.control.FrontController;import net.dreamhui.commands.LoginCommand;public class LoginController extends FrontController{public function LoginController(){initCommands();}/**注册Command*/private function initCommands():void{addCommand(LoginEvent.LOGIN_USER,LoginCommand);}}}


    LoginCommand.as

    package net.dreamhui.commands{import com.adobe.cairngorm.commands.ICommand;import com.adobe.cairngorm.control.CairngormEvent;import mx.controls.Alert;import mx.rpc.IResponder;import net.dreamhui.business.LoginDelegate;import net.dreamhui.control.LoginEvent;import net.dreamhui.model.UserModelLocator;import net.dreamhui.vo.UserVO;public class LoginCommand implements ICommand,IResponder{public function LoginCommand(){}public function execute(event:CairngormEvent):void{//Alert.show("execute");var lgEvent:LoginEvent = LoginEvent(event);var user:UserVO = lgEvent.data;var delegate:LoginDelegate = new LoginDelegate(this);delegate.login(user);}/** * Command实现IResponder接口的两个方法result和fault; * 我看了两份教程,前者是这样的: * 1、Command实现com.adobe.cairngorm.business.Responder接口的onResult和onFault两个方法; * 2、Command实现mx.rpc.IResponder接口的两个方法result和fault; * 因为我在LoginDelegate没能实现将内部变量设置为com.adobe.cairngorm.business.Responder, * 所以,我采用了第二种方案,通过。 * */public function result(event:Object):void{var cuUser:UserVO = event.result as UserVO;if(cuUser){UserModelLocator.getInstance().currentUser = cuUser;//此赋值操作绑定loginYes事件,当输入数据合法时候,将改变当前的登录状态//Alert.show(cuUser.userName);}else{Alert.show("用户名或密码错误,请重新填写");}}public function fault(event:Object):void{trace("服务调用错误"+event.toString());}}}


    LoginDelegate.as

    package net.dreamhui.business{import com.adobe.cairngorm.business.ServiceLocator;import mx.rpc.IResponder;import net.dreamhui.vo.UserVO;public class LoginDelegate{public var responder:IResponder;public var service:Object;public function LoginDelegate(responder:IResponder){this.service = ServiceLocator.getInstance().getRemoteObject("loginService");//this.service = ServiceLocator.getInstance().getService("loginService");//我看的教程里采用下面的做法,程序运行没有问题,只是会有warningthis.responder = responder;}public function login(user:UserVO):void{var call:Object = service.login(user);//call.resultHandler = Delegate.create(responder, responder.onResult);//call.faultHandler = Delegate.create(responder, responder.onFault);//注释掉的部分是教程里的写法,可能是版本的问题,在我这儿是不对的call.addResponder(responder);}}}

    LoginServiceLocator.mxml

    <?xml version="1.0" encoding="utf-8"?><cairngorm:ServiceLocatorxmlns:fx="http://ns.adobe.com/mxml/2009"xmlns:s="library://ns.adobe.com/flex/spark"xmlns:mx="library://ns.adobe.com/flex/mx"xmlns:cairngorm="http://www.adobe.com/2006/cairngorm"><!--~~~~~~~~~~~~~~~~~~~~~~Declarations~~~~~~~~~~~~~~~~~~~~~~--><fx:Declarations><s:RemoteObject id="loginService"destination="loginUser"showBusyCursor="true"/></fx:Declarations></cairngorm:ServiceLocator>

最后工程运行结果:





OK,完成。