[教學] Hello World BlazeDS

繼上篇的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則可分成三種:

  1. application:建立單一 instance
  2. session:每個使用 session 建立一個 instance
  3. 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>

轉載請註明出處

1 意見 :: [教學] Hello World BlazeDS

  1. 請問版大有測試過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的畫面卻一值出步來

    不知版大有遇過這樣問題嗎?