安卓网络客户端--协议的封装和抽取
协议的封装和抽取这块比较复杂,序列化和反序列化,自己做了一点总结,希望大家多多指点。
一.为什么要进行协议封装
以往的处理方式:利用XmlSerializer一点点编写协议序列化代码
存在问题(假设我们有100个请求需要处理):
1、需要将协议中的请求分配给不同的组员进行处理,也就是大部分组员需要学习协议。
2、学习情况检验,是不是所有的组员都已经很好的理解了协议(开协议研讨会)。
3、进入协议开发阶段,类似的代码需要出现100次,由于不同人员处理,过程中很容易出现错误且抽取工作不统一。
4、开发过程中协议修改了,这就需要所有的组员停下手中工作,更改各自编写的请求代码(开会布置)。
这种情况下,就会让我们的开发进程减慢,我们的解决办法是,对协议进行封装和抽取。
二.协议封装的几个原则
1.节点对象化
节点对象: Leaf 、 Header
Oelement、Element(请求及回复)、 Body
Message
2.节点序列化
•序列化原则:自己管自己
•序列化范围:只有请求的节点涉及序列化
•序列化顺序:Leaf、Header、Element、Body、Message
•Message节点提供请求入口
•Message节点提供对外的xml文件数据提供方法
3.请求接口(抽象)化
Element接口(抽象)化,所有请求必须实现该接口或继承该抽象类,同时实现定义的获取请求类型标示和请求序列化的方法。以获取当前销售期信息为例说明
4.协议通用化
•协议格式:xml、json
•协议压缩:wbxml (用于将xml文件进行压缩)、二进制流
•新协议制定和已有协议
下面就以一个彩票客户端的选彩协议为例来说明:
信息发送 (查询指定玩法可销售期信息)
发送消息的协议如下:
<?xml version=”1.0” encoding=”utf-8”?> <message version="1.0"> <header> <agenterid>889931</agenterid> <source>ivr</source> <compress>DES</compress> <messengerid>20091113101533000001</messengerid> <timestamp>20091113101533</timestamp> <digest>7ec8582632678032d25866bd4bce114f</digest> <transactiontype>12002</transactiontype> <username>13200000000</username> </header> <body> <elements> <element> <lotteryid>118</lotteryid> <issues>1</issues> </element> </elements> </body> </message>
三.开始封装,对其中一个叶子节点的序列化.
package cn.piaoye.lottery.protocol; import org.apache.commons.lang3.StringUtils; import org.xmlpull.v1.XmlSerializer; /** * 叶子节点 * 标签名字 * 值 * @author piao * */ public class Leaf { private String tagName; private String value; public Leaf(String tagName, String value) { super(); this.tagName = tagName; this.value = value; } public Leaf(String tagName) { super(); this.tagName = tagName; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } //<agenterid>889931</agenterid> 在这里我们要调用序列化方法,把叶子节点给序列化 /** * 序列化叶子 */ public void serializer(XmlSerializer serializer){ try { serializer.startTag(null,tagName); if(StringUtils.isBlank(value)){ value="";//屏蔽value为空的情况 } serializer.text(value); serializer.endTag(null,tagName); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
四.头信息的封装
package cn.piaoye.lottery.protocol; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Random; import org.apache.commons.codec.digest.DigestUtils; import org.xmlpull.v1.XmlSerializer; import cn.piaoye.lottery.ConstantValue; /** * 头信息进行封装 * @author piao * */ public class Header { //八个叶子 private Leaf agenterid=new Leaf("agenterid", ConstantValue.AGENTERID); private Leaf source=new Leaf("source", ConstantValue.SOURCE); private Leaf compress=new Leaf("compress", ConstantValue.COMPRESS); private Leaf messengerid=new Leaf("messengerid"); private Leaf timestamp=new Leaf("timestamp"); private Leaf digest=new Leaf("digest"); private Leaf transactiontype=new Leaf("transactiontype"); private Leaf username=new Leaf("username"); /** * header部分序列化 */ public void serializer(XmlSerializer serializer,String body){ //第一个叶子节点 /** * messengerid:当前的这个xml的标示 值:时间戳:yyyyMMddHHmmss +六位的随机数 处理方式:SimpleDateFormat DecimalFormat */ SimpleDateFormat dateFormat=new SimpleDateFormat("yyyyMMddHHmmss"); String time=dateFormat.format(new Date()); //获取随机数 Random random=new Random(); int num=random.nextInt(999999)+1;//1 //格式化随机数 DecimalFormat decimalFormat=new DecimalFormat("000000"); String randomNum = decimalFormat.format(num); messengerid.setValue(time+randomNum); timestamp.setValue(time); //MD5的摘要信息 //时间戳+密码+body部分信息。 String md5Info=time+ConstantValue.AGENTER_PASSWORD+body; String md5Hex=DigestUtils.md5Hex(md5Info); digest.setValue(md5Hex); try { serializer.startTag(null, "header"); //叶子 agenterid.serializer(serializer); source.serializer(serializer); compress.serializer(serializer); messengerid.serializer(serializer); timestamp.serializer(serializer); digest.serializer(serializer); transactiontype.serializer(serializer); username.serializer(serializer); serializer.endTag(null, "header"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } //这个我们处理不了,就给他暴露出去 public Leaf getTransactiontype() { return transactiontype; } public Leaf getUsername() { return username; } }
package cn.piaoye.lottery; public interface ConstantValue { String AGENTERID="1000002";//子代理商的标示 String SOURCE="ivr";//信息来源 String COMPRESS="DES";//body部分的加密方式 /** * 子代理商的密钥 */ String AGENTER_PASSWORD = "9ab62a694d8bf6ced1fab6acd48d02f8"; /** * des加密用密钥 */ String DES_PASSWORD = "9b2648fcdfbad80f"; }
对封装的协议进行测试:
public void testHeader() { XmlSerializer serializer = Xml.newSerializer(); try { StringWriter writer = new StringWriter(); serializer.setOutput(writer); serializer.startDocument("utf-8", null); serializer.startTag(null, "message"); Header header=new Header(); header.serializer(serializer, ""); // body serializer.startTag(null, "body"); serializer.endTag(null, "body"); serializer.endTag(null, "message"); serializer.endDocument(); Log.i("XmlTest", writer.toString()); } catch (Exception e) { e.printStackTrace(); } }
生成的xml文件为:
<?xml version='1.0' encoding='utf-8'?> <message> <header> <agenterid> 1000002 </agenterid> <source>ivr</source> <compress> DES </compress> <messengerid> 20121224163229736485 </messengerid> <timestamp> 20121224163229 </timestamp> <digest> a6bcb107c326f21006233dd67d9fc038 </digest> <transactiontype> </transactiontype> <username> </username> </header> <body /> </message>
如果,这篇博客帮您解决了问题,不妨点击一下右下角的【推荐】。如果,您希望更容易地发现我的新博客,不妨点击一下【加关注】。因为,我的热情需要您的肯定和支持!感谢您的阅读,如果文章中有错误或者您有什么好的建议,也欢迎您直接留言批评指教。Thanks,friends! |