其它参考:http://www.programcreek.com/java-api-examples/index.php?api=flex.messaging.io.amf.Amf3Output
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; } }
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是什么意思呢?
这些概念不知道谁定义的,会用是一回事,不过要通透看来还要有许多学术知识才行。