繼上篇的Step by Step Blazeds後,介紹一下Blazeds的功能:Remoting、Message、Proxy
Remoting
概述
BlazeDS Remoting可使 Flash執行在伺服器上的 java程式,可傳值及接收結果, Remoting的傳輸格式是 AMF,格式較小且為二進位傳輸
使用 Remoting
先設定 "安裝目錄\WEB-INF\flex" 下的 remoting-config.xml,加入連線目的及要執行的 Java程式
<destination id="hello"> <properties> <source>idv.gd.HelloWorld</source> <scope>application</scope> </properties> </destination>
destination 為給 Flex 識別的連線名,source 為實際 java 程式所在位置,scope則可分成三種:
- application:建立單一 instance
- session:每個使用 session 建立一個 instance
- require(default):每次連線建立 instance
java存放路徑為 "安裝目錄\WEB-INF\classes",放置位置同 Java package路徑(ex:安裝目錄\WEB-INF\classes\idv\gd\HelloWorld.class) 可執行的檔案為 Java編譯後的檔案(*.class),範例使用了三個方法,程式源始碼如下
package idv.gd; public class HelloWorld{ public String getHello(){ return "Hello world"; } public String sendMsg(String str){ String serverMsg = "[Server]你說的話是:" + str; return serverMsg; } public Object sendObj(Object obj){ return obj; } }
Remoting VO
Flex特有的 "RemoteClass" metadata 是用來指出 Flex 與伺服器上的 VO物件,只要在後面加入伺服器 VO位置,就能自動對應,可傳遞相同的 VO物件。
本地 VO
package vo{ //用來連結遠端的 java object,名稱路徑要相符 [RemoteClass (alias = "idv.gd.MyVO")] public class MyVO{ //parameters 要相符,可有多餘參數 public var userName:String; public var userPWD:String; //public var extraParam:Object; public function MyVO(userName:String = null, userPWD:String = null){ this.userName = userName; this.userPWD = userPWD; } } }
伺服器 VO
package idv.gd; public class MyVO{ public String userName; public String userPWD; }
兩對應之 VO參數要相符,路徑要正確,VO路徑不必含副檔名(idv.gd.MyVO),設定好後,Flex跟伺服器就可傳相同的 VO物件了
範例程式為傳送 VO給伺服器,伺服器收到後回傳 "server" + 原始訊息的 VO給 Flash 主程式:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="main();"> <mx:Script> <![CDATA[ import mx.rpc.remoting.RemoteObject; import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import vo.MyVO; private function main():void{ var myRO:RemoteObject = new RemoteObject(); myRO.destination = "VOTest"; myRO.getVO.addEventListener(ResultEvent.RESULT, resultHandler); myRO.getVO.addEventListener(FaultEvent.FAULT, resultHandler); var myVO:MyVO = new MyVO(); myVO.userName = "GD"; myVO.userPWD = "123"; myRO.getVO(myVO); } private function resultHandler(event:ResultEvent):void{ var myVO:MyVO = MyVO(event.result); msg.text = myVO.userName + "\n" + myVO.userPWD; } private function faultHandler(event:FaultEvent):void{ msg.text = event.message.toString(); } ]]> </mx:Script> <mx:TextArea id="msg" top="10" bottom="10" left="10" right="10"/> </mx:Application>
Java:
package idv.gd; public class Contact{ public MyVO getVO(MyVO vo){ vo.userName = "server=" + vo.userName; vo.userPWD = "server=" + vo.userPWD; return vo; } }
程式原始碼
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="800" height="600" applicationComplete="main();"> <mx:Script> <![CDATA[ import flash.utils.getQualifiedClassName; import flash.utils.getDefinitionByName; import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; private function main():void{ //直接把 Java的方法當實體註冊 myRO.getHello.addEventListener(ResultEvent.RESULT, resultHandler); myRO.sendMsg.addEventListener(ResultEvent.RESULT, resultHandler); myRO.sendObj.addEventListener(ResultEvent.RESULT, resultTypeHandler); myRO.getHello.addEventListener(FaultEvent.FAULT, faultHandler); myRO.sendMsg.addEventListener(FaultEvent.FAULT, faultHandler); myRO.sendObj.addEventListener(FaultEvent.FAULT, faultHandler); //呼叫 Java方法 myRO.getHello(); //試著傳送物件型態資料 myRO.sendObj({ name:"myName", age:18}); //試著傳送陣列型態資料 myRO.sendObj(["myName", 18]); } private function faultHandler(event:FaultEvent):void{ msg.text += event.message + "\n"; } private function resultHandler(event:ResultEvent):void{ msg.text += event.result + "\n"; } private function resultTypeHandler(event:ResultEvent):void{ msg.text += getQualifiedClassName(event.result) + "\n"; } private function sendMsg():void{ myRO.sendMsg(inputMsg.text); } ]]> </mx:Script> <mx:RemoteObject id="myRO" destination="hello" result="resultHandler(event)" fault="faultHandler(event)" /> <mx:Button x="178" y="393" label="send" click="sendMsg()"/> <mx:TextInput x="10" y="393" id="inputMsg"/> <mx:TextArea x="10" y="45" width="502" height="340" id="msg" fontSize="12" /> <mx:Label x="10" y="10" text="RemoteObject 測試" fontSize="16" fontWeight="bold"/> </mx:Application>
BlazeDS Message
概述
Message 可讓多使用者與伺服器溝通,彼此的訊息都會被廣播,可簡單作出聊天室的效果
使用 Message
首先在 "專案目錄\WEB-INF\flex"下有個 messaging-config.xml 的設定檔,打開後加入一個連線識別名
<destination id="chat"/>
整體設定檔如下
<?xml version="1.0" encoding="UTF-8"?> <service id="message-service" class="flex.messaging.services.MessageService"> <adapters> <adapter-definition id="actionscript" class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" /> <!-- <adapter-definition id="jms" class="flex.messaging.services.messaging.adapters.JMSAdapter"/> --> </adapters> <default-channels> <channel ref="my-polling-amf"/> </default-channels> <destination id="chat"/> </service>
開啟設定好的 Flex 專案,使用 consumer、producer與 message 連線,consumer是負責接收來自message的訊息,而 producer 則是負責發送訊息,以下設定 consumer及 producer
<mx:Producer id="myProducer" destination="chat" fault="faultHandler(event);" channelConnect="connectHandler(event)"/> <mx:Consumer id="myConsumer" destination="chat" message="messageHandler(event)" fault="faultHandler(event);" channelConnect="connectHandler(event)"/>
在設定完後並未連線,跟 HttpService一樣,producer需透過 send()指令送出訊息,而 consumer則是以subscribe()訂閱 message訊息
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="main()"> <mx:script> //一開始先把consumer連線 private function main():void{ myConsumer.subscribe(); } private function sendMsg():void{ var message:IMessage = new AsyncMessage(); //body是一個物件 message.body.chatMessage = inputMsg.text; myProducer.send(message); inputMsg.text = ""; }
producer 送出的訊息是一個 AsyncMessage物件,裡面的 body為實際傳送值,型態為物件,可再自定義屬性,範例為送出 chatMessage屬性做為聊天訊息,設定好後執行兩隻程式即可對話。
程式原始碼
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="main()"> <mx:Script> <![CDATA[ import mx.messaging.events.ChannelEvent; import mx.messaging.events.MessageFaultEvent; import mx.rpc.events.FaultEvent; import mx.messaging.events.MessageEvent; import mx.messaging.messages.AsyncMessage; import mx.messaging.messages.IMessage; //一開始先把consumer連線 private function main():void{ myConsumer.subscribe(); } private function sendMsg():void{ var message:IMessage = new AsyncMessage(); //body是一個物件 message.body.chatMessage = inputMsg.text; myProducer.send(message); inputMsg.text = ""; } private function messageHandler(event:MessageEvent):void{ chatDialog.text += event.message.body.chatMessage + "\n"; } private function faultHandler(event:MessageFaultEvent):void{ chatDialog.text += event.faultDetail; } private function connectHandler(event:ChannelEvent):void{ chatDialog.text += event.type + " connect\n"; } ]]> </mx:Script> <mx:Producer id="myProducer" destination="chat" fault="faultHandler(event);" channelConnect="connectHandler(event)"/> <mx:Consumer id="myConsumer" destination="chat" message="messageHandler(event)" fault="faultHandler(event);" channelConnect="connectHandler(event)"/> <mx:Button x="178" y="358" label="send" click="sendMsg()"/> <mx:TextInput x="10" y="358" id="inputMsg"/> <mx:TextArea x="10" y="10" width="502" height="340" id="chatDialog"/> </mx:Application>
BlazeDS Proxy
概述
Proxy可以解決 Flash的跨網域安全性問題,使原本無法存取的遠端網站,藉由本地伺服器存取後再轉給 Flash,如此就不會有 crossdomain的問題,且使用BlazeDS 設定非常方便,也能隨時置換要存取的位置,不必修改 Flash
使用 Proxy
首先在 "專案目錄\WEB-INF\flex"下有個 proxy-config.xml 的設定檔,打開後會看到裡面己有 DefaultHTTP 的 desination,這是用來告訴伺服器,當 Flash 要存取 HTTP 資源時,那些網域要透過伺服器代理處理,透過 <dynamic-url>標籤指定網域,可使用萬字元(*)
<destination id="DefaultHTTP"> <properties> <dynamic-url>http://tw.news.yahoo.com/*</dynamic-url> </properties> </destination>
使用 Flex 連線 dynamic-url: 跟平常的設定一樣,還是使用 url做連結,只是 useProxy要設為 true,讓連線去找伺服器設定
<mx:HTTPService id="dynamicHS" url="http://tw.news.yahoo.com/rss/realtime" result="resultHandler(event)" resultFormat="e4x" showBusyCursor="true" fault="faultHandler(event);" useProxy="true" />
自定義 proxy: 可使用 destination id 作為與 flash的連線識別,告訴 Flash連到 destination 要轉到那個網址去,雖然是外部網址,但Flash是透過本地伺器取值,所以不會有 crossdomain的問題
<destination id="myRSS"> <properties> <url>http://portofreturn.pixnet.net/blog/feed/rss</url> </properties> </destination>
使用 Flex 連線 destination proxy: 使用 destination取代 url,useProxy一樣要設為 true
<mx:HTTPService id="proxyHS" destination="myRSS" result="proxyResultHandler(event)" resultFormat="e4x" showBusyCursor="true" fault="faultHandler(event);" useProxy="true" />
使用 Webservice: 基本設定大致相同,但伺服器端要設定以 soap方式傳輸
<adapters> <adapter-definition id="http-proxy" class="flex.messaging.services.http.HTTPProxyAdapter" default="true"/> <adapter-definition id="soap-proxy" class="flex.messaging.services.http.SOAPProxyAdapter"/> </adapters> <destination id="infoService"> <properties> <wsdl>http://livecycledata.org/services/ProductWS?wsdl</wsdl> <soap>*</soap> </properties> <adapter ref="soap-proxy"/> </destination>
程式原始碼
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#333333, #000000]"> <mx:Script> <![CDATA[ import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; [Bindable] private var rssPath:String = "http://portofreturn.pixnet.net/blog/feed/rss"; private var xml:XML; private function resultHandler(event:ResultEvent):void{ xml = new XML(event.result); msg.text = xml.toXMLString(); } private function proxyResultHandler(event:ResultEvent):void{ //xml = new XML(event.result.body); msg.text = "proxy\n"; msg.text += event.result; } private function faultHandler(event:FaultEvent):void{ msg.text = String(event.message); } private function getRSS(url:String):void{ rssPath = url; myHS.send(); } ]]> </mx:Script> <mx:HTTPService id="myHS" url="{ rssPath}" result="resultHandler(event)" resultFormat="e4x" showBusyCursor="true" fault="faultHandler(event);" /> <mx:HTTPService id="proxyHS" destination="myRSS" result="proxyResultHandler(event)" resultFormat="e4x" showBusyCursor="true" fault="faultHandler(event);" useProxy="true" /> <mx:HTTPService id="dynamicHS" url="http://tw.news.yahoo.com/rss/realtime" result="resultHandler(event)" resultFormat="e4x" showBusyCursor="true" fault="faultHandler(event);" useProxy="true" /> <mx:TextArea left="10" bottom="10" top="41" right="10" id="msg" fontSize="12"/> <mx:ApplicationControlBar left="0" right="0" top="0"> <mx:Button label="Local RSS" click="getRSS('rss.xml');"/> <mx:Button label="pixnet RSS" click="getRSS('http://portofreturn.pixnet.net/blog/feed/rss')"/> <mx:Button label="Chanwei RSS" click="getRSS('http://chanwei.dev.kland.com.tw/security/rss.xml')"/> <mx:Button label="Proxy RSS" click="proxyHS.send();"/> <mx:Button label="dynamic RSS" click="dynamicHS.send();"/> </mx:ApplicationControlBar> </mx:Application>
轉載請註明出處
請問版大有測試過chat這個範例嗎?按照BlazeDS提供的範例sample7來測試,發現自己無法建立這個範例,最後發現是在compile的時候有問題,WEB-INF/flex整個資料夾都是使用原本的範例,MXML的原始碼貼上以後,FLEX出現Channel definition, mx.messaging.channels.RTMPChannel, can not be found.
後來發現在Library path鐘的libs指向WEB-INF/flex/libs,這樣就不會出現這個錯誤訊息,不過經過flex builder編譯之後,chat的畫面卻一值出步來
不知版大有遇過這樣問題嗎?
匿名
2010年11月29日 中午12:33