繼上篇的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