在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
- 在android需要大量使用xml进行网络传输时,如何用面向对象的思路降低xml的耦合性并增加重用性
- android 网络传输序列化的对象------不需要进行xml/json解析
- boost::any在降低模块之间耦合性的应用
- responseXML 属性 如果来自服务器的响应是 XML,而且需要作为 XML 对象进行解析,请使用 responseXML 属性: 请求 books.xml 文件,并解析响应:
- 如何降低一个程序的耦合性
- 如何降低一个程序的耦合性
- 降低程序耦合性的方法
- js如何用面向对象的思路去编写一个程序
- 降低对象之间的耦合关系
- 如何用XSL对XML的数据进行按节点排序?
- 在ASP中如何用xml的方式抓取这个页面的数据?
- 利用jquery进行xml数据的传输
- MQ大大降低了程序的耦合性
- 码农小汪-SPringMVC-基本的理解MVC 降低耦合性~依赖性
- 码农小汪-SPringMVC-基本的理解MVC 降低耦合性~依赖性
- 如何用Google APIs和Google的应用系统进行集成(7)----在把JSON转换成XML数据过程中,JSON数据中包含违背XML数据规范:XML节点名不支持数字的Java解决方案
- 如何用DOM4J编程使用xml schema
- 如何用InputStream作为BIRT的xml数据源
- opnet 路由表
- [think in java]知识点学习
- UncaughtExceptionHandler捕捉异常,保存至SD卡中
- 2015腾讯校招 一面
- ...
- 在android需要大量使用xml进行网络传输时,如何用面向对象的思路降低xml的耦合性并增加重用性
- HttpClient 核心代码
- [寒江孤叶丶的Cocos2d-x之旅_15]Cocos2d-x LUA脚本中对字符串进行Base64加解密/编解码 (LUA Base64 加解密/编解码)
- UBUNTU 14.04解决sublime text 3 中文无法输入的问题
- strtok()函数
- 理解wait和notify
- Hibernate实现many-to-many的映射关系
- 自定义TabBar第一种方案
- 2014.10.10