前言
在微信订阅号和支付宝生活号日常开发中,我们会涉及到对象和XML之间的相互转换。
比如我们可以利用StringBuilder去直接拼接来构造XML
/** * 构造基础的响应消息 * * @return */ public static String buildBaseAckMsg(String fromUserId) { StringBuilder sb = new StringBuilder(); sb.append(""); sb.append(""); sb.append(""); sb.append("" + Calendar.getInstance().getTimeInMillis() + ""); sb.append(""); sb.append(""); return sb.toString(); }
作为像我这么懒得程序员,肯定会去找大佬写好的轮子,这就是我和XStream相遇的契机。下面我们一起走进XStream;
一.关于 XStream
Xstream 是一个简单的库,用于将对象序列化为 XML 然后再序列化回来。
二.简单入门
2.1 创建要序列化的类
这里有几个简单的类,XStream 可以将这些类的实例转换为 XML,然后再转换回来。
public class Person { private String firstname; private String lastname; private PhoneNumber phone; private PhoneNumber fax; // ... constructors and methods}public class PhoneNumber { private int code; private String number; // ... constructors and methods}
注意: 注意这些字段是私有的。Xstream 不关心字段的可见性。不需要getters or setters。此外,XStream 并不限制你拥有一个默认构造函数。
2.2 初始化 XStream
引入依赖
com.thoughtworks.xstream xstream 1.4.10
要使用 XStream,只需实例化 XStream 类:
XStream xstream = new XStream();
2.3.将序列化对象转为xml
让我们创建一个 Person 实例并填充它的字段:
Person person = new Person("Joe", "milo"); person.setPhone(new PhoneNumber(123,"1234-456")); person.setFax(new PhoneNumber(123,"999-456"));
现在,要将其转换为XML,只需要简单的调用XStream的toXML()方法
String xml = xstream.toXML(person);
现在,为了使 XStream 输出的 XML 更简洁,可以为 XML 元素名的自定义类名创建别名。这是使用 XStream 所需的惟一映射类型,当然这是可选的。
xstream.alias("person",Person.class);
我们会发现XML变得更简洁
2.4.将XML反序列化对象
首先,我们重写Person对象的toString()
@Override public String toString() { return "Person{" + "firstname='" + firstname + ''' + ", lastname='" + lastname + ''' + ", phone=" + phone + ", fax=" + fax + '}'; }
要重构一个对象,我们只需调用fromXML()方法
XStream xstream = new XStream(); xstream.alias("person",Person.class); //xml字符串 String xmldemo = "<?xml version="1.0" ?>Joemilo1231234-456123999-456"; Person o = (Person)xstream.fromXML(xmldemo); System.out.println(o.toString());
123
123
三.高级入门
在高级入门中,我们以支付宝生活号开发为例,采用Xstream的注解开发来完成事件订阅过程中的xml报文相关的操作
3.1 项目搭建
首先我们搭建项目springboot-xstream,当然你可以在
https://gitee.com/milogenius/milogenius-springboot
找到源代码,案例位于springboot-xstream模块下面。由于案例代码太多,强烈建议大家下载源代码案例自己跑一跑。
3.2 相关类解释
3.3 和XStream相关的类
1.AlipayXmlMessage
package com.milo.xstream.xml;import com.thoughtworks.xstream.annotations.XStreamAlias;import com.thoughtworks.xstream.annotations.XStreamConverter;import lombok.Data;import lombok.extern.slf4j.Slf4j;import java.io.InputStream;import java.io.Serializable;import java.util.Map;/** * 支付宝生活号推送过来的xml消息 * @author milogenius * @date 2020/4/4 15:29 * */@Data@Slf4j@XStreamAlias("XML")public class AlipayXmlMessage implements Serializable { private static final long serialVersionUID = -3586245291677274914L; /** * 使用dom4j解析的存放所有xml属性和值的map. */ private Map allFieldsMap; /// // 以下都是支付宝生活号推送过来的消息的xml的element所对应的属性 /// /**AppId*/ //AppId--->xml中的字段 //appId --->pojo中的字段 @XStreamAlias("AppId") @XStreamConverter(value = XStreamCDataConverter.class) private String appId; /**用户userid,用户唯一标识*/ @XStreamAlias("FromAlipayUserId") @XStreamConverter(value = XStreamCDataConverter.class) private String fromAlipayUserId; /**消息创建时间*/ @XStreamAlias("CreateTime") private Long createTime; /**消息类型*/ @XStreamAlias("MsgType") @XStreamConverter(value = XStreamCDataConverter.class) private String msgType; /**事件类型*/ @XStreamAlias("EventType") @XStreamConverter(value = XStreamCDataConverter.class) private String eventType; /**用户从特定场景关注,带的自定义参数值*/ @XStreamAlias("ActionParam") @XStreamConverter(value = XStreamCDataConverter.class) private String actionParam; /**支付宝用户信息*/ @XStreamAlias("UserInfo") @XStreamConverter(value = XStreamCDataConverter.class) private String userInfo; /**消息id 用于消息去重*/ @XStreamAlias("MsgId") private String msgId; public static AlipayXmlMessage fromXml(String xml) { //修改支付宝生活号变态的消息内容格式,方便解析 xml = xml.replace("<?xml version="1.0" encoding="gbk"?>", ""); final AlipayXmlMessage xmlMessage = XStreamTransformer.fromXml(AlipayXmlMessage.class, xml); xmlMessage.setAllFieldsMap(XmlUtils.xml2Map(xml)); return xmlMessage; } public static AlipayXmlMessage fromXml(InputStream is) { return XStreamTransformer.fromXml(AlipayXmlMessage.class, is); }}
2.AlipayXmlOutMessage
package com.milo.xstream.outxml;import com.milo.xstream.builder.AckBuilder;import com.milo.xstream.xml.XStreamCDataConverter;import com.milo.xstream.xml.XStreamTransformer;import com.thoughtworks.xstream.annotations.XStreamAlias;import com.thoughtworks.xstream.annotations.XStreamConverter;import lombok.Data;import java.io.Serializable;/** * 响应XML * @author milogenius * @date 2020/4/4 11:57 * */@XStreamAlias("xml")@Datapublic abstract class AlipayXmlOutMessage implements Serializable { private static final long serialVersionUID = -381382011286216263L; /**接受者userid*/ @XStreamAlias("ToUserId") @XStreamConverter(value = XStreamCDataConverter.class) protected String toUserId; /**支付宝生活号appid*/ @XStreamAlias("AppId") @XStreamConverter(value = XStreamCDataConverter.class) protected String appId; /**创建时间*/ @XStreamAlias("CreateTime") protected Long createTime; /**消息类型*/ @XStreamAlias("MsgType") @XStreamConverter(value = XStreamCDataConverter.class) protected String msgType; @XStreamAlias("response") protected Response response; @XStreamAlias("sign") protected String sign; @XStreamAlias("sign_type") protected String signType; /** * 获得ack builder * @return */ public static AckBuilder ACK() { return new AckBuilder(); } @SuppressWarnings("unchecked") public String toXml() { StringBuilder builder = new StringBuilder(); String xml = XStreamTransformer.toXml((Class) this.getClass(), this); builder.append("<?xml version="1.0" encoding="gbk"?>"); builder.append(xml); return builder.toString(); }}
3.XStreamCDataConverter
package com.milo.xstream.xml;import com.thoughtworks.xstream.converters.basic.StringConverter;/** * 自定义转换器 * @author milogenius * @date 2020/4/4 10:56 * */public class XStreamCDataConverter extends StringConverter { @Override public String toString(Object obj) { return ""; }}
相关注解说明
@XStreamAlias用于定义XStream类或字段别名的注释
@XStreamConverter用于声明转换器的注释
3.4 测试
XmlDemoTest
package com.milo.xstream;import com.milo.xstream.outxml.AlipayXmlOutMessage;import com.milo.xstream.xml.AlipayXmlMessage;/** * @author milogenius * @date 2020-04-04 11:49 */public class XmlDemoTest { public static void main(String[] args) { //xml --->pojo String bizContent = "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; AlipayXmlMessage alipayXmlMessage = AlipayXmlMessage.fromXml(bizContent); // System.out.println(alipayXmlMessage); //pojo --->xml AlipayXmlOutMessage mpXmlOutMessage = AlipayXmlOutMessage.ACK().toUserId("123456").appId("99999999").build(); String xml = mpXmlOutMessage.toXml(); System.out.println(xml); }}
3.5测试结果
3.5.1 xml ---->pojo
3.5.2 pojo --->xml
四.总结
通过上面的一些小案例,我们学习Xstream的基本用法和注解用法,文章到此为止,谢谢大家阅读;