编程技术是改变世界的力量。
本站
当前位置:网站首页 > 后端语言 > 正文

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

gowuye 2024-04-04 11:54 13 浏览 0 评论

前言

在微信订阅号和支付宝生活号日常开发中,我们会涉及到对象和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的操作,大家可以阅读:

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

三.高级入门

在高级入门中,我们以支付宝生活号开发为例,采用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<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")
@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((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的基本用法和注解用法,文章到此为止,谢谢大家阅读;

相关推荐

嵌入式C语言中常量的应用实例(嵌入式c语言中常量的应用实例是什么)

常量,我们都知道,就是数值保持不变的量。在C语言中,常量一旦初始化了,它的值将在整个程序运行周期内,不允许发生任何变化。常量与变量是相对的,我们实际项目中经常会用到它。定义常量的两种方式C语言中主要有...

C语言编程基础知识汇总学习,适合初学者!更新常量知识

(二)整型常量整型常量有3种形式:十进制整型常量、八进制整型常量和十六进制整型常量。(注意:c语言中没有直接表示二进制的整型常量,在c语言源程序中不会出现二进制。)书写方式如下:十进制整型常量:123...

【C语言】第二章第六节:字符串常量

第二章第六节:字符串常量。下表C语言中的常用转义字符。·字符形式功能:ASCIl码(十进制形式)。→\t水平制表(横向跳格:跳到下一个tab位置)。→\b退格8。→\r回车(不换行,光标移到本行行首)...

「GCTT 出品」Go 系列教程——5. 常量

这是我们Golang系列教程的第五篇。定义在Go语言中,术语”常量”用于表示固定的值。比如5、-89、IloveGo、67.89等等。看看下面的代码:varaint=50v...

每日C语言-常量指针、指针常量、指向常量的指针常量

一、常量指针1)什么是常量指针?通过该指针不可以修改其所指向存储单元中的值指针本身即地址可以被修改2)定义:类型说明符const*指针变量;类型说明符表示指针所指向存储单元中的值得数据类型指针...

C语言-符号常量、常变量、变量之我见

更新内容:新增音频。音频和文章一起更配oHello,大家好,又和大家见面了~~相信很多朋友们听了C语言的“符号常量”、“常变量”、“变量”后还是对这三者一脸懵逼吧。不管老师怎么歇斯底里地讲解,同学们迷...

零基础带你学习C语言:四:探索常量与变量

前言常量与变量学习;一:分析:short、float、long类型#include<stdio.h>intmain(){shortage=18;floatweight=12...

C语言中是如何定义常量的?那定义字符串呢?

常量有整型常量、浮点型常量、字符型常量及字符串常量。‘常量定义是指定义符号常量,用一个标识符来代表一个常量,通过宏定义预处理指令来实现。常量的定义:#definecount60这就定义了一个常量...

C语言符号常量的优点,会是那几点?

符号常量是一个常量,是不变量,所以,在编译的时候,就把符号常量出现的地方,替换为符号常量对应的常量。符号常量一般用户定义一个全局使用的数据,而且要改变该数据的时候,只需要改变符号常量的值,代码中引用符...

嵌入式开发- C语言数据类型-常量(c语言嵌入式是干嘛的)

基本数据类型的常量-掌握**整型常量:**常量是指在程序运行期间其数值不发生变化的数据。整型常量通常简称为整数整数可以是十进制数、八进制数、十六进制数八进制06334十六进制0xd1...

c语言解剖课:只读变量、常量、字面量傻傻分不清?

写在前面本篇主题的缘起,是因为一个计算机专业的大学生在和我讨论c语言问题时,说const常量如何如何,我说变量被const修饰了,还是变量,不是“常量”。他给了我一个截图:他说大模型都是这样回答的,变...

C/C++编程笔记:C数组、字符串常量和指针!三分钟弄懂它

想弄懂C语言中数组和指针的关系吗?这篇文章就占据你三分钟时间,看完你肯定会有收获!数组数组声明为数据类型名称[constant-size],并将一个数据类型的一个或多个实例分组到一个可寻址的位...

C语言入门到精通【第008讲】——C语言常量

C语言常量常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。常量可以是任何的基本数据类型,比如整数常量、浮点常量、字符常量,或字符串字面值,也有枚举常量。常量就像是常规的变量,只不过常...

这是C语言无法修改得东西,C语言基础教程之常量解析

常量是指程序在执行期间不会改变的固定值。这些固定值也称为文字。常量可以是任何基本数据类型,如整数常量,浮点常量,字符常量或字符串文字,还有枚举常量。常量被视为常规变量,除了它们的值在定义后无法修改。整...

C语言中的单精度、双精度、常量等都有什么意思?

刚接触C语言时,对于常量,变量,浮点,单精度,双精度等问题的理解,大都很模糊不清,其实在程序运行过程中,其值不能改变的量称为常量。如12、0、-3为整型常量,4.6、-1.23为实型常量,'a'、'...

取消回复欢迎 发表评论: