在android需要大量使用xml进行网络传输时,如何用面向对象的思路降低xml的耦合性并增加重用性

来源:互联网 发布:学汉语拼音的软件 编辑:程序博客网 时间:2024/05/21 19:34

根据一个需求来进行分析。在项目中由于需要经常通过发送接收xml进行网络通信,从服务器中抓取数据

如果不对xml做优化,需要写大量的serializer.startTag(null, "header");serializer.endTag(null, "header"); ......如何进行优化呢.


我们来看这个需求,这是一个按照文档写出的xml文件作为发送方,

<?xml version=”1.0” encoding=”utf-8”?><message version="1.0">     <header>                          <agenterid>889931</agenterid>            <source>ivr</source>            <compress>DES</compress>             <messengerid>20131013101533000001</messengerid>             <timestamp>20131013101533</timestamp>            <digest>7ec8582632678032d25866bd4bce114f</digest>            <transactiontype>12002</transactiontype>            <username>13200000000</username>     </header>     <body>            <elements>                  <element>                         <lotteryid>118</lotteryid>                         <issues>1</issues>                  </element>            </elements>      </body></message>

里面的节点意义我就不说了,header表示请求的协议,一般不会变,只有messageid ,timestamp  digest 会有规律的变化,username 和 transactiontype会无规律的变化,body中的elements元素需要进行加密处理,处理完的样子时<body>sdfsfsdasd34rnh34u53434534534o</body>  是进行des加密的


下面我们根据面向对象的方式来对这个xml进行优化。首先分析这个xml


好的,下面我们开始写简单的叶子和值

package com.jrrjw.caipiao.net.protocal;import org.xmlpull.v1.XmlSerializer;/** * 简单的叶子和值 <name>value</name> *  * @author Idea *  */public class Leaf {private String tagName;private String tagValue;public void setTagValue(String tagValue) {this.tagValue = tagValue;}/** * 对于一个xml  节点的名称时必须的 *  * @param tagName */public Leaf(String tagName) {this.tagName = tagName;}public Leaf(String tagName, String tagValue) {this.tagName = tagName;this.tagValue = tagValue;}/** * ͨ通过调用它 的对象提供serializer序列化节点 *  * @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.jrrjw.caipiao.net.protocal;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 com.jrrjw.caipiao.ConstantValue;public class Header {// 这些都是规定好的协议头// <agenterid>889931</agenterid>private Leaf agenterid = new Leaf("agenterid", ConstantValue.AGENTERID);// <source>ivr</source>private Leaf source = new Leaf("source", ConstantValue.SOURCE);// <compress>DES</compress>private Leaf compress = new Leaf("compress", ConstantValue.COMPRESS);// <messengerid>20131013101533000001</messengerid>private Leaf messengerid = new Leaf("messengerid");// <timestamp>20131013101533</timestamp>private Leaf timestamp = new Leaf("timestamp");// <digest>7ec8582632678032d25866bd4bce114f</digest>private Leaf digest = new Leaf("digest");// <transactiontype>12002</transactiontype>private Leaf transactiontype = new Leaf("transactiontype");// <username>13200000000</username>private Leaf username = new Leaf("username");/** * 由调用者提供序列化对象,由于header里的都是固定好的,这里就不用抽取了。 *  * @param serializer */public void serializerHeader(XmlSerializer serializer, String body) {// 首先保证上面实例化的叶子都有tagValue值// messengerid 时间戳+随机6位数SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");String time = simpleDateFormat.format(new Date());Random random = new Random();int num = random.nextInt(999999) + 1;messengerid.setTagValue(time + num);timestamp.setTagValue(time);// digest 由時間戳+密码+body原文  然后进行md5加密  StringBuffer buffer = new StringBuffer();buffer.append(time);buffer.append(ConstantValue.AGENTER_PASSWORD);buffer.append(body);String v = DigestUtils.md5Hex(buffer.toString());digest.setTagValue(v);try {serializer.startTag(null, "header");agenterid.serializerLeaf(serializer);source.serializerLeaf(serializer);compress.serializerLeaf(serializer);messengerid.serializerLeaf(serializer);timestamp.serializerLeaf(serializer);digest.serializerLeaf(serializer);transactiontype.serializerLeaf(serializer);username.serializerLeaf(serializer);serializer.endTag(null, "header");} catch (Exception e) {e.printStackTrace();}}public Leaf getTransactiontype() {return transactiontype;}public Leaf getUsername() {return username;}}

header写完,下面开始写body部分了,首先考虑一下这个element的写法,看代码,看到最后你就知道为什么这么写了。

package com.jrrjw.caipiao.net.protocal;import org.xmlpull.v1.XmlSerializer;/** * 存放叶子的集合,做成抽象类,由子类自定义实现 * @author Idea * */public abstract class Element {/** * 每个element都需要序列化 * @param serializer */public abstract void serializerElement(XmlSerializer serializer);/** * 每一个Element都需要唯一标示符 * @return */public abstract String getTransactionType();}

下面开始写body

package com.jrrjw.caipiao.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.jrrjw.caipiao.ConstantValue;import com.jrrjw.caipiao.utils.DES;public class Body {private List<Element> elements = new ArrayList<Element>();public void serializerBody(XmlSerializer serializer) {try {serializer.startTag(null, "body");serializer.startTag(null, "elements");if (elements != null) {for (Element element : elements) {element.serializerElement(serializer);}}serializer.endTag(null, "elements");serializer.endTag(null, "body");} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}public List<Element> getElements() {return elements;}/** * 获取body里面的DES加密数据,为了安全需要加密,这段可以在JNI里实现,这里简单起见 * @return */public String getBodyInsideDESInfo(){// 加密数据String wholeBody = getWholeBody();String orgDesInfo=StringUtils.substringBetween(wholeBody, "<body>", "</body>");// 加密// 加密调试——2天// ①加密算法实现不同// ②加密的原始数据不同DES des=new DES();return des.authcode(orgDesInfo, "DECODE", ConstantValue.DES_PASSWORD);}/** * 由于需求说明,这个方法的目的是在header里提供一个body的未加密数据在digest中 * @return */public String getWholeBody() {try {// 这里不能用XmlSerializer serializer 至于为什么自己考虑一下就明白了XmlSerializer temp = Xml.newSerializer();StringWriter writer = new StringWriter();temp.setOutput(writer);temp.startTag(null, "body");temp.startTag(null, "elements");if (elements != null) {for (Element element : elements) {element.serializerElement(temp);}}temp.endTag(null, "elements");temp.endTag(null, "body");//因为这个temp并没有startDocument 所以他不会自动写闭合标签,也就不会自动关闭,所以要手动刷一下temp.flush();return writer.toString();} catch (Exception e) {e.printStackTrace();}return null;}}

最后写Message

package com.jrrjw.caipiao.net.protocal;import java.io.StringWriter;import org.xmlpull.v1.XmlSerializer;import android.util.Xml;import com.jrrjw.caipiao.ConstantValue;/** * 这里实现整个xml的框架 * @author Idea * */public class Messager {private Header header = new Header();private Body body = new Body();public Header getHeader() {return header;}public Body getBody() {return body;}/** * 序列化协议 */public void serializerMessage(XmlSerializer serializer) {try {// <message version="1.0">serializer.startTag(null, "message");// MUST follow a call to startTag() immediatelyserializer.attribute(null, "version", "1.0");header.serializerHeader(serializer, body.getWholeBody());// 获取完整的body//body.serializerBody(serializer);这里就没有调用这个方法,serializer.startTag(null, "body");serializer.text(body.getBodyInsideDESInfo());serializer.endTag(null, "body");serializer.endTag(null, "message");} catch (Exception e) {e.printStackTrace();}}/** * 获取请求的xml文件 *  * @return */public String getXml(Element element) {if (element == null) {throw new IllegalArgumentException("element is null");}// 请求标示需要设置,请求内容需要设置header.getTransactiontype().setTagValue(element.getTransactionType());body.getElements().add(element);// 序列化XmlSerializer serializer = Xml.newSerializer();StringWriter writer = new StringWriter();// This method can only be called just after setOutputtry {serializer.setOutput(writer);serializer.startDocument(ConstantValue.ENCONDING, null);this.serializerMessage(serializer);serializer.endDocument();return writer.toString();} catch (Exception e) {e.printStackTrace();}return null;}}

xml已经基本抽象出来可以作为通用了,那么我们怎么用呢。

package com.jrrjw.caipiao.net.protocal.element;import org.xmlpull.v1.XmlSerializer;import com.jrrjw.caipiao.net.protocal.Element;import com.jrrjw.caipiao.net.protocal.Leaf;/** * 这个类的目的时定义body体的内容 * @author Idea * */public class TestElement extends Element{//可以赋值,这样做更好private Leaf lotteryid = new Leaf("lotteryid");private Leaf issues = new Leaf("issues","1");public Leaf getLotteryid() {return lotteryid;}//public Leaf getIssues() {//return issues;//}@Overridepublic void serializerElement(XmlSerializer serializer) {try {serializer.startTag(null, "element");lotteryid.serializerLeaf(serializer);issues.serializerLeaf(serializer);serializer.endTag(null, "element");} catch (Exception e) {e.printStackTrace();}}@Overridepublic String getTransactionType() {return "121212";}}

最后看看测试结果


package com.jrrjw.caipiao.test;import android.test.AndroidTestCase;import com.jrrjw.caipiao.net.protocal.Messager;import com.jrrjw.caipiao.net.protocal.element.TestElement;public class XmlTest extends AndroidTestCase{public void test1(){TestElement element  = new TestElement();element.getLotteryid().setTagValue("118");Messager messager = new Messager();messager.getHeader().getUsername().setTagValue("idea");String value = messager.getXml(element);System.out.println(value);}}
这里用的android测试需要加上

<instrumentation android:targetPackage="com.jrrjw.caipiao" android:name="android.test.InstrumentationTestRunner" /> <uses-library android:name="android.test.runner" />

这里只是把发送的内容抽象了出来,也可以把接收的内容抽象到一起,其实很简单,这里就不写了。


用到的des加密工具类

package com.jrrjw.caipiao.utils;import java.security.InvalidKeyException;import java.security.Key;import java.security.NoSuchAlgorithmException;import javax.crypto.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.NoSuchPaddingException;import javax.crypto.spec.SecretKeySpec;import org.apache.commons.codec.binary.Base64;public class DES {public DES() {}public static DES getInstance(String key) throws NoSuchPaddingException,NoSuchAlgorithmException {return getInstance(getKeyByStr(key));}public static DES getInstance(byte key[]) throws NoSuchPaddingException,NoSuchAlgorithmException {DES des = new DES();if (des.key == null) {SecretKeySpec spec = new SecretKeySpec(key, "DES");des.key = spec;}des.cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");return des;}public byte[] encrypt(byte b[]) throws InvalidKeyException,BadPaddingException, IllegalBlockSizeException,IllegalStateException {byte byteFina[] = null;cipher.init(1, key);byteFina = cipher.doFinal(b);return byteFina;}public byte[] decrypt(byte b[]) throws InvalidKeyException,BadPaddingException, IllegalBlockSizeException,IllegalStateException {byte byteFina[] = null;cipher.init(2, key);byteFina = cipher.doFinal(b);return byteFina;}public static byte[] getKeyByStr(String str) {byte bRet[] = new byte[str.length() / 2];for (int i = 0; i < str.length() / 2; i++) {Integer itg = new Integer(16 * getChrInt(str.charAt(2 * i))+ getChrInt(str.charAt(2 * i + 1)));bRet[i] = itg.byteValue();}return bRet;}private static int getChrInt(char chr) {int iRet = 0;if (chr == "0".charAt(0))iRet = 0;if (chr == "1".charAt(0))iRet = 1;if (chr == "2".charAt(0))iRet = 2;if (chr == "3".charAt(0))iRet = 3;if (chr == "4".charAt(0))iRet = 4;if (chr == "5".charAt(0))iRet = 5;if (chr == "6".charAt(0))iRet = 6;if (chr == "7".charAt(0))iRet = 7;if (chr == "8".charAt(0))iRet = 8;if (chr == "9".charAt(0))iRet = 9;if (chr == "A".charAt(0))iRet = 10;if (chr == "B".charAt(0))iRet = 11;if (chr == "C".charAt(0))iRet = 12;if (chr == "D".charAt(0))iRet = 13;if (chr == "E".charAt(0))iRet = 14;if (chr == "F".charAt(0))iRet = 15;return iRet;}private Key key;private Cipher cipher;/** * @interpret 进行base64加密操作 * @param text * @param keyString * @return String */public String encrypt(String text, String keyString) {String body = null;try {DES des = DES.getInstance(keyString);byte[] b = des.encrypt(text.getBytes("UTF8"));body = new String(Base64.encodeBase64(b));} catch (Exception ex) {}return body;}/** * @interpret 进行base64进行解密 * @param text * @param keyString * @return String */public String decrypt(String text, String keyString) {String body = null;try {DES des = DES.getInstance(keyString);byte[] b = Base64.decodeBase64(text.getBytes());body = new String(des.decrypt(b), "UTF8");} catch (Exception e) {e.printStackTrace();}return body;}/** *  * @param content  内容 * @param operation 加密或解密 * @param key 使用到的密钥:固定长度 * @return */public String authcode(String content, String operation, String key){String encontent = null;if (operation != null && operation.equals("DECODE")) {encontent = encrypt(content,key);} else if (operation != null && operation.equals("ENCODE")) {encontent = decrypt(content,key);}return encontent;}public static void main(String[] args) {DES des = new DES();System.out.println(des.authcode("wewweewewew=","DECODE","0102030405060708"));//加密System.out.println(des.authcode("d8fPhfd9JkW99p8aqhtVIA==","ENCODE","0102030405060708"));//解密}}


用到的jar包

commons-codec.jar

commons-lang3-3.0-beta.jar


0 0
原创粉丝点击