问题:今天我在Flex的module中使用RemoteObject的方式与服务端进行AMF的远程数据调用。第一次切换到module时是没有问题的,但第二次切换到module时,发现总是报错,无法完成远程调用。为此困惑极了。
我在remoting访问时,使用了一个自定义的参数类:
package VO
{
[RemoteClass(alias="ServiceLibrary.SystemFramework.UserInfoSearchCondition")]
public class UserInfoSearchConditionVO
{
public function UserInfoSearchConditionVO()
{
}
public var UserName:String;
public var DepartmentId:String;
}
}
这个定义里使用到了:[RemoteClass(alias="ServiceLibrary.SystemFramework.UserInfoSearchCondition")]
这就是本地对象与“远程服务端类”的别名定义,这个大家都应该知道的。
远程调用时:
var condition:UserInfoSearchConditionVO=new UserInfoSearchConditionVO();
condition.UserName=txtSearchUserName.text;
var resp1:Responder=new Responder(onUserSearchCountSuccess,onUserSearchCountFaild);
nc.call("ServiceLibrary.SystemFramework.UserInfoFacade.GetUserInfoCountByCondition",resp1,condition);
但不知道为什么,在第一次Module时加载是可以的。在第二次加载module时,此“注册”信息会丢失。
解决方法:需要明确声明此注册信息,代码如下:
import flash.net.registerClassAlias;
import mx.messaging.messages.RemotingMessage;
import VO.UserInfoSearchConditionVO;
registerClassAlias("ServiceLibrary.SystemFramework.UserInfoSearchCondition", UserInfoSearchConditionVO);
以上的代码可以放在自己的module里,或者也可以直接放在Application上,声明一次也就可以了,子Module不需要更申明了。
最后的代码我帖出来,如果你能看懂就最好了,看不懂我也没办法了:)
<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo" layout="vertical" width="100%" height="100%"
creationComplete="module1_creationCompleteHandler(event)" >
<fx:Script>
<![CDATA[
import mx.events.ListEvent;
import AppConfig.Connection;
import mx.events.FlexEvent;
import mx.controls.Alert;
public var nc:NetConnection;
import mx.collections.ArrayCollection;
public var pageCount:int=10;
public var curPage:int=0;
public var totalCount:int=0;
//这里就是需要申明注册别名的地方。
import flash.net.registerClassAlias;
import mx.messaging.messages.RemotingMessage;
import VO.UserInfoSearchConditionVO;
registerClassAlias("ServiceLibrary.SystemFramework.UserInfoSearchCondition", UserInfoSearchConditionVO);
protected function module1_creationCompleteHandler(event:FlexEvent):void
{
// TODO Auto-generated method stub
nc=new NetConnection();
nc.objectEncoding=ObjectEncoding.AMF3;
var gatewayUrl:String =AppConfig.Connection.getInstance().connectionString;
nc.addEventListener(NetStatusEvent.NET_STATUS,netStateHandle);
nc.connect(gatewayUrl);
}
protected function netStateHandle(evt:NetStatusEvent):void
{
Alert.show("连接出错了!","出错了");
}
protected function btnSearch_clickHandler(event:MouseEvent):void
{
// TODO Auto-generated method stub
BindGrid();
}
protected function BindGrid():void
{
var condition:UserInfoSearchConditionVO=new UserInfoSearchConditionVO();
condition.UserName=txtSearchUserName.text;
var resp1:Responder=new Responder(onUserSearchCountSuccess,onUserSearchCountFaild);
nc.call("ServiceLibrary.SystemFramework.UserInfoFacade.GetUserInfoCountByCondition",resp1,condition);
var resp2:Responder=new Responder(onUserSearchSuccess,onUserSearchFaild);
nc.call("ServiceLibrary.SystemFramework.UserInfoFacade.GetUserInfoByCondition",resp2,condition,curPage,pageCount);
}
protected function onUserSearchCountSuccess(re:Object):void{
this.totalCount= re as int;
if(curPage>0)
this.btnPrev.visible=true;
else
this.btnPrev.visible=false;
if((curPage+1) * pageCount >=totalCount)
this.btnNext.visible=false;
else
this.btnNext.visible=true;
}
protected function onUserSearchCountFaild(re:String):void{
Alert.show("获取数据出错!","出错了");
}
protected function onUserSearchSuccess(re:ArrayCollection):void{
gridUser.dataProvider =re;
}
protected function onUserSearchFaild(re:String):void{
Alert.show("获取数据出错!","出错了");
}
protected function btnNext_clickHandler(event:MouseEvent):void
{
// TODO Auto-generated method stub
curPage++;
BindGrid();
}
protected function btnPrev_clickHandler(event:MouseEvent):void
{
// TODO Auto-generated method stub
curPage--;
BindGrid();
}
protected function gridUser_itemClickHandler(event:ListEvent):void
{
// TODO Auto-generated method stub
this.currentState="edit";
}
]]>
</fx:Script>
<mx:states>
<s:State name="view"/>
<s:State name="edit"/>
</mx:states>
<s:HGroup width="100%" height="100%">
<s:Panel width="250" height="100%" title="用户管理">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:HGroup width="100%" height="29">
<s:TextInput id="txtSearchUserName" height="29" width="162"/>
<mx:Button id="btnSearch" label="查询mailto:"%20icon="@Embed(source='assets/images/search.png')" height="29" labelPlacement="right" click="btnSearch_clickHandler(event)">
</mx:Button>
</s:HGroup>
<mx:HRule width="100%"/>
<mx:ButtonBar height="20" height.view="32">
<mx:dataProvider>
<fx:Object label="新增mailto:"%20icon="@Embed(source='assets/images/Add.png')" />
<fx:Object label="删除mailto:"%20icon="@Embed(source='assets/images/Remove.png')" />
</mx:dataProvider>
</mx:ButtonBar>
<mx:DataGrid id="gridUser" width="100%" height="100%" itemClick="gridUser_itemClickHandler(event)">
<mx:columns>
<mx:DataGridColumn headerText="用户名" dataField="UserName"/>
</mx:columns>
</mx:DataGrid>
<s:HGroup x="393" y="264" width="100%" height="26">
<mx:LinkButton label="上一页" id="btnPrev" visible="false" click="btnPrev_clickHandler(event)"/>
<mx:LinkButton label="下一页" id="btnNext" visible="false" click="btnNext_clickHandler(event)"/>
</s:HGroup>
</s:Panel>
<mx:VRule height="100%" baseColor="#A75757"/>
<s:Panel id="pnlUserEdit" horizontalCenter="0" verticalCenter="0" width="100%" height="100%" dropShadowVisible="true" title="用户信息"
includeIn="edit">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<mx:Form width="100%" height="100%">
<mx:FormItem label="帐号:" required="true" >
<s:TextInput id="account" >
</s:TextInput>
</mx:FormItem>
<mx:FormItem label="密码:" required="true">
<s:TextInput id="pwd" displayAsPassword="true">
</s:TextInput>
</mx:FormItem>
<mx:FormItem>
<s:CheckBox id="chkRememberMe" selected="true" label="下次记住我">
</s:CheckBox>
</mx:FormItem>
<mx:FormItem horizontalAlign="right">
<s:Button label="登录" id="btnSave" >
</s:Button>
</mx:FormItem>
</mx:Form>
</s:Panel>
</s:HGroup>
</mx:Module>
最后,我再主张一下我的设计的原则:
在客户端与服务端进行远程数据调用时,我不太主张采用“简单参数”模式,比如查询用户功能吧,我可以使用username,deparmentId...等等参数来进行参数调用,但这样有个扩展性问题:那就是当以后要添加“查询条件”时,不得不修改接口。这就是会导致客户端要修改N个调用地方,服务端也要进行接口修改,这就会带来很大的扩展问题。
因此,我建议可以自定义一个“Condition查询类”与“服务端”的相对应,这样接口的参数就只需要一个,而且类型不变。
以后如果要扩展“查询条件”时,只需要在“客户端”添加一个属性,并赋值就OK了。在“服务端”则也只要添加属性,并修改实现代码就OK了,不再需要修改两端的“接口”了。。