AMF這東西跟服務端交互還是挺爽的,搜了一下,發現網上沒有很完整的例子,大多只有一段。今天整理下之前的項目代碼,抽出amf來上個教程,怕以后忘記了。本教程寫的是http,Servlet交互的方式。socket方式要寫粘包,代碼麻煩,不寫了。
調試環境
1.java jdk 1.6
2.flash builder 4.5
3.blazeDS(下載地址http://opensource.adobe.com/wiki/display/blazeds/Downloads/,最新4.X版本下載好像被牆了,懶得翻的可以從http://opensource.adobe.com/wiki/display/blazeds/download+blazeds+3這里下載舊版本。
知識前提:
1.懂得配置java,eclipse,flex環境
2.懂得socket,Servlet等相關知識
首先先上web開發http方式交互的例子:
1.用eclipse新建一個web項目,名為TestWeb。選j2ee,把blazeDS相關包添入。
2.新建VO,名為TestResult代碼如下:(注意串化)
package model;
import java.io.Serializable;
public class TestResult implements Serializable
{
private static final long serialVersionUID = 5297328693553539438L;
private int id;
private String name;
private String desc;
private int[] ls;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public int[] getLs() {
return ls;
}
public void setLs(int[] ls) {
this.ls = ls;
}
}
3.新建amf類,名為TestAMF,代碼如下:
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.zip.DeflaterOutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.TestResult;
import flex.messaging.io.SerializationContext;
import flex.messaging.io.amf.Amf3Input;
import flex.messaging.io.amf.Amf3Output;
public class TestAMF extends HttpServlet {
private static final long serialVersionUID = -1079073749217155506L;
private SerializationContext context = new SerializationContext();
// post接收
public void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
response.setContentType("application/x-gzip-compressed");
// 這部份是用來解析接收as的vo數據的
try {
long sTime = System.currentTimeMillis();
Amf3Input amt = new Amf3Input(context);
amt.setInputStream(request.getInputStream());
TestResult tr = (TestResult) amt.readObject();
long uTime = System.currentTimeMillis() - sTime;
System.out.println("接收到客戶端消息,"+tr.getName());
System.out.println(tr+"解析成功,用時"+uTime+"ms");
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.out.println("解析錯誤");
}
// 這部份是用來生成vo發給客房端的
Amf3Output out = new Amf3Output(context);
DeflaterOutputStream stream = new DeflaterOutputStream(new DataOutputStream(response.getOutputStream()));
out.setOutputStream(stream);
int[] ls = {11,22,33};
TestResult tvo = new TestResult();
tvo.setId(21);
tvo.setName("Pelephone");
tvo.setDesc("發消息給客戶端\nhttp://cnblogs.com/pelephone");
tvo.setLs(ls);
out.writeObject(tvo);
stream.finish();
}
// get接收
public void doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {
doPost(request, response);
}
}
4.修改WEB-INF下的web.xml文件,代碼如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>
test
</servlet-name>
<servlet-class>
TestAMF
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>/TestAMF</url-pattern>
</servlet-mapping>
</web-app>
5.啟動web服務端.(一般默認的地址是http://127.0.0.1:8080/TestWeb)
6.用flash builder(flex)新建一個as項目,名為TestAMF.
7.新建VO,名為TestResult,結構跟java端的統一,代碼如下:
package model
{
public class TestResult
{
public var id:int;
public var name:String;
public var desc:String;
public var ls:Array;
}
}
8.主類TestAMF.as代碼如下:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.net.URLRequestMethod;
import flash.net.registerClassAlias;
import flash.utils.ByteArray;
import flash.utils.getTimer;
import model.TestResult;
public class TestAMF extends Sprite
{
private var _loader:URLLoader;
public function TestAMF() {
trace("TestAMF");
// 一定要先串化vo類才能解析此vo
registerClassAlias("model.TestResult",TestResult);
_loader = new URLLoader();
_loader.dataFormat = URLLoaderDataFormat.BINARY;
_loader.addEventListener(Event.COMPLETE, loaderHandler);
_loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, loaderHandler);
_loader.addEventListener(IOErrorEvent.IO_ERROR, loaderHandler);
var request:URLRequest = new URLRequest("http://127.0.0.1:8080/TestWeb/TestAMF");
var tvo:TestResult = new TestResult();
tvo.id = 123123;
tvo.name = "testtest";
tvo.desc = "發消息給服務端\n Pelephone";
tvo.ls = [1,2,222,333,444];
// post二進制數據給服務端
var out:ByteArray = new ByteArray();
out.writeObject(tvo);
request.data = out;
request.method = URLRequestMethod.POST;
_loader.load(request);
}
private function loaderHandler(event:*):void {
trace(event.type);
switch(event.type) {
case Event.COMPLETE:
// 接收到的服務端數據
var start:Number=getTimer();
var byte:ByteArray = _loader.data as ByteArray;
byte.uncompress();
var obj:TestResult = byte.readObject();
var end:Number=getTimer();
trace("耗時:" + (end - start) + "毫秒");
trace(obj);
break;
}
}
}
}
9.F11編譯as項目即可看到結果了。
運行后可以看到,amf解析效率還是相當不錯的。我用999個對象數組放進去解析,就10個ms內搞定。不過跟.net有個相同的地方,就是第一次解析慢。啟動第一次解析用了幾百個毫秒,估計是生成緩存在內存吧。還有一個不足的地方是amf無法解析Vector類型,可能有方法吧,我暫時沒找到。相比java,as的泛型對象顯得很憋腿…
最后疑惑一下,很多人跟我AMF協議,我就奇怪,網絡協議一般就是http,socket,udp。socket是4層傳輸,http是7層傳輸。AMF從應用上看只是一種數據格式而已,像xml,json這樣,只是通過代碼將這些格式進行轉換。在百度百科搜到的資料我更加疑惑了,有一句是這樣“AMF協議是基於Http協議的.”http是7層協議,那AMF算什么? 而且我寫游戲的時候都是用socket+amf的呀,基於http是什么意思呢?
這些概念不知道誰定義的,會用是一回事,不過要通透看來還要有許多學術知識才行。