一.为什么要进行协议封装
以往的处理方式:利用XmlSerializer一点点编写协议序列化代码
存在问题(假设我们有100个请求需要处理):
1、需要将协议中的请求分配给不同的组员进行处理,也就是大部分组员需要学习协议。
2、学习情况检验,是不是所有的组员都已经很好的理解了协议(开协议研讨会)。
3、进入协议开发阶段,类似的代码需要出现100次,由于不同人员处理,过程中很容易出现错误且抽取工作不统一。
4、开发过程中协议修改了,这就需要所有的组员停下手中工作,更改各自编写的请求代码(开会布置)。
这种情况下,就会让我们的开发进程减慢,我们的解决办法是,对协议进行封装。下面来看一下今天学的“查询指定玩法可销售期信息”的协议。
二.协议的划分和几个原则
Ⅰ.分为:1.非敏感数据 2. 敏感数据(需要加密)
Ⅱ.原则:
1.节点对象化:Leaf、Header、Oelement、Element(请求及回复)、Body
2.节点序列化
•序列化原则:自己管自己
•序列化范围:只有请求的节点涉及序列化
•序列化顺序:Leaf、Header、Element、Body、Message
•Message节点提供请求入口
•Message节点提供对外的xml文件数据提供方法
3.请求接口(抽象)化
Element接口(抽象)化,所有请求必须实现该接口或继承该抽象类,同时实现定义的获取请求类型标示和请求序列化的方法。以获取当前销售期信息为例说明
4.协议通用化
•协议格式:xml、json
•协议压缩:wbxml (用于将xml文件进行压缩)、二进制流
•新协议制定和已有协议
三.协议的封装
下面先来看一下平时咱们进行xml解析的格式(仅为事例):
XmlSerializer serializer = Xml.newSerializer(); try { StringWriter writer = new StringWriter(); serializer.setOutput(writer); serializer.startDocument(ContentValues.SERIALIZER_ENCODING, null); serializer.startTag(null, "message"); serializer.startTag(null, "header"); serializer.endTag(null, "header"); serializer.startTag(null, "body"); serializer.endTag(null, "body"); serializer.endTag(null, "message"); serializer.endDocument(); } catch (Exception e) { e.printStackTrace(); }
由此可见代码冗余,极易出错,维护成本高!
处理思路:①.公共部分一个人处理(面向对象思想):a、包含数据;b、序列化
②不同请求交给项目组其他成员完成
封装Leaf节点:
package com.itheima.lottery.net.protocal; import org.xmlpull.v1.XmlSerializer; public class Leaf { private String tagName; private String tagValue; public String getTagValue() { return tagValue; } public void setTagValue(String tagValue) { this.tagValue = tagValue; } public String getTagName() { return tagName; } public Leaf(String tagName, String tagValue) { super(); this.tagName = tagName; this.tagValue = tagValue; } public Leaf(String tagName) { super(); this.tagName = tagName; } /** * 序列化叶子 * @param serializer */ public void serializerLeaf(XmlSerializer serializer){ try { serializer.startTag(null, tagName); if(tagValue == null){ tagValue = ""; } serializer.text(tagValue); serializer.endTag(null, tagName); } catch (Exception e) { e.printStackTrace(); } } }
封装header节点:
package com.itheima.lottery.net.protocal; 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 android.annotation.SuppressLint; import com.itheima.lottery.utils.Constant; public class Header { // 常量 private Leaf agenterid = new Leaf("agenterid", Constant.AGENTERID); // agenterid:代理商唯一标示 private Leaf source = new Leaf("source", Constant.SOURCE); // source:来源(android/iphone,数据采集---数据挖掘) private Leaf compress = new Leaf("compress", Constant.COMPRESS); // compress:加密算法(body里面数据加密) // 计算获取的数据 private Leaf timestamp = new Leaf("timestamp"); // 时间戳 private Leaf messengerid = new Leaf("messengerid"); // 时间戳+六位的随机数 private Leaf digest = new Leaf("digest"); // 时间戳+代理密码+完整body明文 // 协议封装无法处理 private Leaf transactiontype = new Leaf("transactiontype"); // 请求的唯一的标示 private Leaf username = new Leaf("username"); // 用户名 @SuppressLint("SimpleDateFormat") public void serialHeader(XmlSerializer serializer,String body){ // 时间戳 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); String date = dateFormat.format(new Date()); timestamp.setTagValue(date); // 时间戳+六位的随机数 Random random = new Random(); int number = random.nextInt(999999) + 1; DecimalFormat decimalFormat = new DecimalFormat("000000"); messengerid.setTagValue(date + decimalFormat.format(number)); // 时间戳+代理密码+完整body明文 String tagValue = date + Constant.AGENTER_PASSWORD + body; tagValue = DigestUtils.md5Hex(tagValue); digest.setTagValue(tagValue); try { serializer.startTag(null, "header"); agenterid.serializerLeaf(serializer); source.serializerLeaf(serializer); compress.serializerLeaf(serializer); timestamp.serializerLeaf(serializer); messengerid.serializerLeaf(serializer); digest.serializerLeaf(serializer); transactiontype.serializerLeaf(serializer); username.serializerLeaf(serializer); serializer.endTag(null, "header"); } catch (Exception e) { } } public Leaf getTransactiontype() { return transactiontype; } public Leaf getUsername() { return username; } }
Element节点请求接口(抽象)化
package com.itheima.lottery.net.protocal; import org.xmlpull.v1.XmlSerializer; public abstract class Element { public abstract void serializerElement(XmlSerializer serializer); /** * 请求标识 * @return */ public abstract String getTransactiontype(); }
Body节点封装:
package com.itheima.lottery.net.protocal; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.xmlpull.v1.XmlSerializer; import android.util.Xml; import com.itheima.lottery.utils.Constant; import com.itheima.lottery.utils.DES; public class Body { private List<Element> elements = new ArrayList<Element>(); public List<Element> getElements() { return elements; } public void serializerBody(XmlSerializer serializer) { try { serializer.startTag(null, "body"); for (Element element : elements) { element.serializerElement(serializer); } serializer.endTag(null, "body"); } catch (Exception e) { e.printStackTrace(); } } // 获取整个body 明文内容 public String getWholeBody() { try { XmlSerializer tempSerializer = Xml.newSerializer(); StringWriter writer = new StringWriter(); tempSerializer.setOutput(writer); serializerBody(tempSerializer); tempSerializer.flush(); return writer.toString(); } catch (Exception e) { e.printStackTrace(); } return null; } /** * @return 获取到body里面加密的数据 */ public String getInsideDesInfo(){ String wholeBody = getWholeBody(); String insideBody = StringUtils.substringBetween(wholeBody, "<body>", "</body>"); DES des = new DES(); return des.authcode(insideBody, "DECODE", Constant.DES_PASSWORD); } }
构成的整个Message,即完成“查询指定玩法可销售期信息”协议的序列化:
package com.itheima.lottery.net.protocal; import java.io.StringWriter; import org.xmlpull.v1.XmlSerializer; import com.itheima.lottery.utils.Constant; import android.util.Xml; public class Message { private Header header = new Header(); private Body body = new Body(); public Header getHeader() { return header; } public void setHeader(Header header) { this.header = header; } public Body getBody() { return body; } public void setBody(Body body) { this.body = body; } /** 消息序列化 * @param serializer */ public void serializerMessage(XmlSerializer serializer){ try { serializer.startTag(null, "message"); serializer.attribute(null, "version", "1.0"); header.serialHeader(serializer, body.getWholeBody()); // body 内容要加密 serializer.startTag(null, "body"); serializer.text(body.getInsideDesInfo()); serializer.endTag(null, "body"); serializer.endTag(null, "message"); } catch (Exception e) { e.printStackTrace(); } } /** 获取指定请求用的xml * @param element * @return */ public String getXml(Element element){ if(element == null){ throw new IllegalArgumentException("填空值,你这不是逗逼吗?"); } header.getTransactiontype().setTagValue(element.getTransactiontype()); body.getElements().add(element); XmlSerializer serializer = Xml.newSerializer(); try { StringWriter writer = new StringWriter(); serializer.setOutput(writer); serializer.startDocument(Constant.ENCODING, true); serializerMessage(serializer); serializer.endDocument(); return writer.toString(); } catch (Exception e) { e.printStackTrace(); } return null; } }