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

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> 轻松搞定XML和对象之间的互转,就它了!

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

前言

在微信订阅号和支付宝生活号日常开发中,我们会涉及到对象和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
    groupIdcom.thoughtworks.xstream/groupId
    artifactIdxstream/artifactId
    version1.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);
轻松搞定XML和对象之间的互转,就它了!

现在,为了使 XStream 输出的 XML 更简洁,可以为 XML 元素名的自定义类名创建别名。这是使用 XStream 所需的惟一映射类型,当然这是可选的。


xstream.alias("person",Person.class);

我们会发现XML变得更简洁

轻松搞定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" ?personfirstnameJoe/firstnamelastnamemilo/lastnamephonecode123/codenumber1234-456/number/phonefaxcode123/codenumber999-456/number/fax/person";
        Person o = (Person)xstream.fromXML(xmldemo);
        System.out.println(o.toString());
轻松搞定XML和对象之间的互转,就它了!

关于更多关于Xstream的操作,大家可以阅读:

https://www.cnblogs.com/jpfss/p/9836465.html

三.高级入门

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

3.1 项目搭建

首先我们搭建项目 springboot-xstream,当然你可以在

https://gitee.com/milogenius/milogenius-springboot

找到源代码,案例位于 springboot-xstream模块下面。由于案例代码太多,强烈建议大家下载源代码案例自己跑一跑。

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

3.2 相关类解释

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

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 MapString, 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")
@Data
public 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((ClassAlipayXmlOutMessage) 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 = "XMLn" +
                "    AppId![CDATA[2014070100171523]]/AppIdn" +
                "    FromUserId![CDATA[20882837462837462837462837461234]]/FromUserIdn" +
                "    FromAlipayUserId![CDATA[2088283746283746]]/FromAlipayUserIdn" +
                "    CreateTime![CDATA[1405943673657]]/CreateTimen" +
                "    MsgType![CDATA[event]]/MsgTypen" +
                "    EventType![CDATA[follow]]/EventTypen" +
                "    ActionParam![CDATA[{"scene":{"sceneId": "1234"}}]]/ActionParamn" +
                "    AgreementId![CDATA[]]/AgreementIdn" +
                "    AccountNo![CDATA[]]/AccountNon" +
                "    UserInfo![CDATA[{"logon_id":"135****1009","user_name":"*iuxu527"}]]/UserInfon" +
                "/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

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

3.5.2 pojo —xml

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

四.总结

通过上面的一些小案例,我们学习Xstream的基本用法和注解用法,文章到此为止,谢谢大家阅读;

END

Java面试题专栏

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

欢迎长按下图关注公众号后端技术精选

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

原文始发于微信公众号(后端技术精选):轻松搞定XML和对象之间的互转,就它了!

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> 轻松搞定XML和对象之间的互转,就它了!