Mapping Value Object
上次我們在Linux中測試過BlazeDS AMF的remote功能,現在我們來試試看在BlazeDS中的Remote Server回傳的Value Object 來映射 Flex端的Value Object。
ActionScript可使用flash.net.registerClassAlias來做Mapping Value Object:
- 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
Step4.將SongData.class與SongService.class配置到BlazeDS的位置上
- 將SongService.class放至/opt/tomcat6/webapps/blazedsAMF/WEB-INF/classes/com/jt/remote
- 將SongData.class放至/opt/tomcat6/webapps/blazedsAMF/WEB-INF/classes/com/jt/valueObject
PS.這是照之前
Linux上配置BlazeDS的設定,因此路徑會是這樣,實際請依你的配置路徑,在WEB-INF/classes底下的路徑就是你JAVA的package設定。
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")]註解掉,測試一下。