一.为什么要进行协议封装
以往的处理方式:利用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;
    }
}