写点什么

轻松搞定 XML 和对象之间的互转,就它了!

用户头像
麦洛
关注
发布于: 2021 年 04 月 21 日
轻松搞定XML和对象之间的互转,就它了!

前言

在微信订阅号和支付宝生活号日常开发中,我们会涉及到对象和 XML 之间的相互转换。



比如我们可以利用 StringBuilder 去直接拼接来构造 XML


    /**     * 构造基础的响应消息     *      * @return     */    public static String buildBaseAckMsg(String fromUserId) {        StringBuilder sb = new StringBuilder();        sb.append("<XML>");        sb.append("<ToUserId><![CDATA[" + fromUserId + "]]></ToUserId>");        sb.append("<AppId><![CDATA[" + AlipayServiceEnvConstants.APP_ID + "]]></AppId>");        sb.append("<CreateTime>" + Calendar.getInstance().getTimeInMillis() + "</CreateTime>");        sb.append("<MsgType><![CDATA[ack]]></MsgType>");        sb.append("</XML>");        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

引入依赖


<dependency>    <groupId>com.thoughtworks.xstream</groupId>    <artifactId>xstream</artifactId>    <version>1.4.10</version></dependency>
复制代码


要使用 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\" ?><person><firstname>Joe</firstname><lastname>milo</lastname><phone><code>123</code><number>1234-456</number></phone><fax><code>123</code><number>999-456</number></fax></person>";        Person o = (Person)xstream.fromXML(xmldemo);        System.out.println(o.toString());
复制代码



关于更多关于 Xstream 的操作,大家可以阅读XStream使用详解

三.高级入门

在高级入门中,我们以支付宝生活号开发为例,采用 Xstream 的注解开发来完成事件订阅过程中的 xml 报文相关的操作

3.1 项目搭建

首先我们搭建项目springboot-xstream,当然你可以在这里找到源代码,案例位于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<String, Object> 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<AlipayXmlOutMessage>) this.getClass(), this); builder.append("<?xml version=\"1.0\" encoding=\"gbk\"?>\n"); 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 "<![CDATA[" + super.toString(obj) + "]]>"; }
}
复制代码


相关注解说明


@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 = "<XML>\n" + " <AppId><![CDATA[2014070100171523]]></AppId>\n" + " <FromUserId><![CDATA[20882837462837462837462837461234]]></FromUserId>\n" + " <FromAlipayUserId><![CDATA[2088283746283746]]></FromAlipayUserId>\n" + " <CreateTime><![CDATA[1405943673657]]></CreateTime>\n" + " <MsgType><![CDATA[event]]></MsgType>\n" + " <EventType><![CDATA[follow]]></EventType>\n" + " <ActionParam><![CDATA[{\"scene\":{\"sceneId\": \"1234\"}}]]></ActionParam>\n" + " <AgreementId><![CDATA[]]></AgreementId>\n" + " <AccountNo><![CDATA[]]></AccountNo>\n" + " <UserInfo><![CDATA[{\"logon_id\":\"135****1009\",\"user_name\":\"*iuxu527\"}]]></UserInfo>\n" + "</XML>"; 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 的基本用法和注解用法,文章到此为止,谢谢大家阅读;

发布于: 2021 年 04 月 21 日阅读数: 43
用户头像

麦洛

关注

与其等待未来,不如创造未来 2020.04.10 加入

微信搜一搜"爱写Bug的麦洛" 公众号关注我,我们一起写bug

评论

发布
暂无评论
轻松搞定XML和对象之间的互转,就它了!