Mapping Value Object
上次我們在Linux中測試過BlazeDS AMF的remote功能,現在我們來試試看在BlazeDS中的Remote Server回傳的Value Object 來映射 Flex端的Value Object。
- Linux上配置Tomcat + BlazeDS請參照Linux上配置BlazeDS
- registerClassAlias( "remote端 value object Class path" , flash端 value object Class path);
Flex中可使用MetaData tags(後設標籤) 來做Mapping Value Object:
- [RemoteClass(alias="value object Class path")]
Remote端配置:
Setp1.撰寫Remote端的值物件SongData
//JAVA SongData (值物件) package com.jt.valueObject; public class SongData { public SongData() { super(); } private String _name; public String getName() { return _name; } public void setName(String name) { _name = name; } private String _vocalist; public String getVocalist() { return _vocalist; } public void setVocalist(String vocalist) { _vocalist = vocalist; } private String _type; public String getType() { return _type; } public void setType(String type) { _type = type; } private int _length; public int getLength() { return _length; } public void setLength(int length) { _length = length; } }
Step2.撰寫Remote Service的類別SongService
//JAVA SongService (服務呼叫API) package com.jt.remote; import com.jt.valueObject.SongData; public class SongService { public SongService() { super(); } public SongData getSongData() { SongData data = new SongData(); data.setName("誰公平"); data.setVocalist("李威"); data.setType("Top"); data.setLength(30000); return data; } }
檔案結構如下圖:
Step3.編譯SongService.java與SongData.java
- 在你使用Eclipse會幫你編譯這兩隻檔案,你也可以使用命令模式java-d編譯檔案。
- 命令模式在所在路徑在src時 :
- javac -d ../classes com/jt/remote/SongService.java
- javac -d ../classes com/jt/valueObject/SongData.java
- 將SongService.class放至/opt/tomcat6/webapps/blazedsAMF/WEB-INF/classes/com/jt/remote
- 將SongData.class放至/opt/tomcat6/webapps/blazedsAMF/WEB-INF/classes/com/jt/valueObject
Step5.設定BlazeDS的配置檔remoting-config.xml
- 如果你是跟著我Linux配置BlazeDS文章的話路徑會在opt/tomcat6/webapps/blazedsAMF/WEB-INF/flex/remoting-config.xml
- sudo gedit opt/tomcat6/webapps/blazedsAMF/WEB-INF/flex/remoting-config.xml
在檔案內容中加入:
<destination id="Remote_GetSong"> <properties> <source>com.jt.remote.SongService</source> </properties> </destination>
Step6.撰寫Flex程式來測試Mapping
//Flex的值物件SongData ,請參考JAVA中的SongData做比較
package com.jt.valueObject { //mapping,alias是指java中valueObject Class的所在路徑。 [RemoteClass(alias="com.jt.valueObject.SongData")] public class SongData { public function SongData() { super(); } private var _name:String; public function get name():String { return _name; } public function set name(value:String):void { if( _name != value) { _name = value; } } private var _vocalist:String; public function get vocalist():String { return _vocalist; } public function set vocalist(value:String):void { if( _vocalist != value) { _vocalist = value; } } private var _type:String; public function get type():String { return _type; } public function set type(value:String):void { if( _type != value) { _type = value; } } private var _length:int; public function get length():int { return _length; } public function set length(value:int):void { if( _length != value) { _length = value; } } } }
//Flex的應用程式
<?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" minWidth="955" minHeight="600" applicationComplete="completeHandler(event)" > <s:layout> <s:HorizontalLayout/> </s:layout> <fx:Script> <![CDATA[ import com.jt.valueObject.SongData; import flash.net.registerClassAlias; import mx.events.FlexEvent; import mx.messaging.ChannelSet; import mx.messaging.channels.AMFChannel; import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.rpc.remoting.Operation; import mx.rpc.remoting.RemoteObject; //Remote Operation private var _channelSet:ChannelSet; private var _amfChannel:AMFChannel; private var _remoteObject:RemoteObject; private var _operation:Operation; private var _data:Object; protected function completeHandler(event:FlexEvent):void { //as3方式設定mapping (java值物件路徑 , as3值物件類) //registerClassAlias("com.jt.valueObject.SongData", SongData); initRemoteData(); initRemoteOpertion(); initBtnListener(); } private function initRemoteData():void { _data = createRemoteData(); } protected function createRemoteData():Object { var data:Object = new Object(); //blazeds的AMF Server Service服務位址 data.uri = "http://127.0.0.1:8400/blazedsAMF/messagebroker/amf"; data.channelSetID = "my-amf"; //服務程式來源path(由classes之後算起) data.source = "com.jt.remote.SongService"; //操作method名稱 data.name = "getSongData"; data.destination = "Remote_GetSong"; return data; } private function initRemoteOpertion():void { initChannelSet(); initAMFChannel(); addChannel(); initRemoteObject(); initOperation(); afterInitOPeration(); } private function initChannelSet():void { _channelSet = new ChannelSet(); } private function initAMFChannel():void { _amfChannel = new AMFChannel(_data.channelSetID , _data.uri); } private function addChannel():void { _channelSet.addChannel(_amfChannel); } private function initRemoteObject():void { _remoteObject = new RemoteObject(); _remoteObject.destination = _data.destination; _remoteObject.channelSet = _channelSet; _remoteObject.source = _data.source; } private function initOperation():void { _operation = new Operation(); _operation.name = _data.name; } private function afterInitOPeration():void { _remoteObject.operations = {getSongData:_operation}; _remoteObject.addEventListener(ResultEvent.RESULT , onResult); _remoteObject.addEventListener(FaultEvent.FAULT , onFault); } protected function onResult(e:ResultEvent):void { var v:SongData; //有這行 ,後設標籤的mapping就會成功, 如果沒有這行 就沒辦法mapping,很怪異。 output.text = e.result.toString(); } protected function onFault(e:FaultEvent):void { output.text = "Remote失敗"; } private function initBtnListener():void { btn.addEventListener(MouseEvent.MOUSE_DOWN , callGetSongData); } protected function callGetSongData(event:MouseEvent):void { _remoteObject.getSongData(); } ]]> </fx:Script> <s:Panel width="300" height="200" title="ValueTest"> <s:layout> <s:VerticalLayout/> </s:layout> <s:TextArea id="output" width="100%" height="100%"/> </s:Panel> <s:Button id="btn" label="call getSongData"/> </s:Application>
- 執行應用程式前記得,要把tomcat運作起來
- 我們在onResult(e:ResultEvent)中下斷點以便觀察e.result
- 執行應用程式
- 點擊瀏覽畫面上的Button
我們可以看到,e.result為一個SongData,代表mapping成功
然後我們將onResult(e:ResultEvent)中的var v:SongData;給註解掉,然後再執行一次應用程式,你會發現e.result竟然變成ObjectProxy了,代表mapping失敗。
至於為什麼會這樣,目前還不知道,但若使用flash.net.registerClassAlias來做mapping則沒有這樣的問題。
registerClassAlias的用法:
- registerClassAlias("com.jt.valueObject.SongData", SongData);
第一個參數是Remote端中,值物件的所在路徑。
第二個參數是Flex端中,值物件的類。
registerClassAlias方式是flashPlayer API因此flash、Flex都可使用。
你可以將應用程式中的registerClassAlias("com.jt.valueObject.SongData", SongData);拿掉註解,然後將SongData的[RemoteClass(alias="com.jt.valueObject.SongData")]註解掉,測試一下。