Java XML解析: 序列化 反序列化

Java解析XML的类库很多,本文记录用XStream库对XML的处理

背景
实际开发中,应用报文的格式一般都是JSON和XML;JSON大家都很熟悉(优秀类库:GSON/FastJson/Jackson),但对XML的解析可能并不熟悉,这主要是因为XML一般用于特定的领域:如金融和支付行业,想要和银联及网联对接,XML是少不了的

XStream的使用
XStream是解析XML的一款轻量级类库,简单快捷。下面以网联的交易查询接口为例,记录XML的序列化和反序列化的相关使用方法
在这里插入图片描述

报文结构如下:
在这里插入图片描述

  1. 创建对应的类(具体类信息添加在文末)
    在这里插入图片描述

  2. 创建XStream工具类

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class XmlUtil {

    /**
     *
     * @param obj 要序列化的对象
     * @return 序列化后的xml字符串
     */
    public static String toXml(Object obj) {

        XStream xStream = new XStream();
        xStream.autodetectAnnotations(true); // 自动发现注解

        try {
            return xStream.toXML(obj);
        } catch (Exception e) {
            throw new RuntimeException("Serialization object to xml error: " + e.getMessage());
        }
    }

    /**
     *
     * @param is XML字符串的字节流
     * @param targetClazz xml反序列化的目标类
     * @param <T>
     * @return 目标类对象
     */
    public static <T> T fromXml(InputStream is, Class<T> targetClazz) {

        XStream xStream = new XStream();
        // 设置安全模式
        XStream.setupDefaultSecurity(xStream);
        // 允许反序列化的类
        xStream.allowTypes(new Class[] {TransStatusInquiryResponse.class});
         
        xStream.processAnnotations(targetClazz); // 反序列化的类

        try {
            return (T) xStream.fromXML(is);
        } catch (Exception e) {
            throw new RuntimeException("Deserialization from xml to object error: " + e.getMessage());
        }
    }
}
  1. 测试序列化和反序列化的结果
public class Test {

    public static final String XML_NS = "name_space_string";
    public static final String ISO_DATE_TIME = "yyyy-MM-dd'T'HH:mm:ss";

    public static final String responseXml = "<root xmlns=\"name_space_string\">\n" +
            "  <MsgHeader>\n" +
            "    <MsgTp>epcc.302.001.01</MsgTp>\n" +
            "    <IssrId>ICBC00001</IssrId>\n" +
            "    <Drctn>21</Drctn>\n" +
            "    <SignSN>87654321</SignSN>\n" +
            "    <NcrptnSN></NcrptnSN>\n" +
            "    <DgtlEnvlp></DgtlEnvlp>\n" +
            "  </MsgHeader>\n" +
            "  <MsgBody>\n" +
            "    <SysRtnInf>\n" +
            "      <SysRtnCd>00000000</SysRtnCd>\n" +
            "      <SysRtnDesc></SysRtnDesc>\n" +
            "      <SysRtnTm>2020-11-29T15:41:15</SysRtnTm>\n" +
            "    </SysRtnInf>\n" +
            "    <BizInf>\n" +
            "      <RPFlg>foo</RPFlg>\n" +
            "      <OriSysRtnCd>foo</OriSysRtnCd>\n" +
            "      <OriSysRtnDesc>foo</OriSysRtnDesc>\n" +
            "      <OriBizstsCd></OriBizstsCd>\n" +
            "      <OriBizStsDesc></OriBizStsDesc>\n" +
            "      <OriTrxctgy>0115</OriTrxctgy>\n" +
            "      <OriTrxId>20201128888888888888888800022</OriTrxId>\n" +
            "      <OriTrxStatus>foo</OriTrxStatus>\n" +
            "      <DbtrBankId>foo</DbtrBankId>\n" +
            "      <CdtrBankId>foo</CdtrBankId>\n" +
            "      <OriTrxAmt>foo</OriTrxAmt>\n" +
            "      <OriBatchId>foo</OriBatchId>\n" +
            "      <OriSgnNo>foo</OriSgnNo>\n" +
            "      <PyerAcctTp>foo</PyerAcctTp>\n" +
            "      <PyerAcctId>foo</PyerAcctId>\n" +
            "      <PyerAcctNm>foo</PyerAcctNm>\n" +
            "      <AcctshrtId>foo</AcctshrtId>\n" +
            "      <ResfdAcctshrtId>foo</ResfdAcctshrtId>\n" +
            "    </BizInf>\n" +
            "  </MsgBody>\n" +
            "</root>";

    public static void main(String[] args) {

        String xmlStr = XmlUtil.toXml(buildRequestObj());

        System.out.println(xmlStr);

        System.out.println("--------------------------");
        TransStatusInquiryResponse inquiryResponse = XmlUtil.fromXml(new ByteArrayInputStream(responseXml.getBytes(StandardCharsets.UTF_8)), TransStatusInquiryResponse.class);
        System.out.println(inquiryResponse.toString());
    }

    private static TransStatusInquiryRequest buildRequestObj() {

        TransStatusInquiryRequest inquiryRequest = new TransStatusInquiryRequest();
        inquiryRequest.setXmlns(XML_NS);

        MsgRequestHeader requestHeader = new MsgRequestHeader();
        requestHeader.setSndDt(DateTimeFormatter.ofPattern(ISO_DATE_TIME).format(LocalDateTime.now()));
        requestHeader.setMsgTp("epcc.301.001.01");
        requestHeader.setIssrId("ICBC00001");
        requestHeader.setDrctn("11");
        requestHeader.setSignSn("12345678");
        requestHeader.setNcrptnSn("");
        requestHeader.setDgtlEnvlp("");

        inquiryRequest.setMsgRequestHeader(requestHeader);

        MsgRequestBody requestBody = new MsgRequestBody();
        requestBody.setInstgId("12345678901234");
        requestBody.setRPFlg("2");

        OriginTrxInfo originTrxInfo = new OriginTrxInfo();
        originTrxInfo.setOriTrxCtgy("0115");
        originTrxInfo.setOriTrxId("20201128888888888888888800022");
        originTrxInfo.setOriTrxDtTm(DateTimeFormatter.ofPattern(ISO_DATE_TIME).format(LocalDateTime.now()));
        originTrxInfo.setOriAcctTp("00");
        originTrxInfo.setOrisgnNo("");

        requestBody.setOriginTrxInfo(originTrxInfo);

        inquiryRequest.setMsgRequestBody(requestBody);

        return inquiryRequest;
    }
}

结果如下:

序列化,组装交易查询的请求报文:
<root xmlns="name_space_string">
  <MsgHeader>
    <SndDt>2020-11-29T15:46:55</SndDt>
    <MsgTp>epcc.301.001.01</MsgTp>
    <IssrId>ICBC00001</IssrId>
    <Drctn>11</Drctn>
    <SignSN>12345678</SignSN>
    <NcrptnSN></NcrptnSN>
    <DgtlEnvlp></DgtlEnvlp>
  </MsgHeader>
  <MsgBody>
    <InstgId>12345678901234</InstgId>
    <RPFlg>2</RPFlg>
    <OriTrxInf>
      <OriTrxCtgy>0115</OriTrxCtgy>
      <OriTrxId>20201128888888888888888800022</OriTrxId>
      <OriTrxDtTm>2020-11-29T15:46:55</OriTrxDtTm>
      <OriAcctTp>00</OriAcctTp>
      <OrisgnNo></OrisgnNo>
    </OriTrxInf>
  </MsgBody>
</root>

--------------------------
反序列化响应报文,结果如下:
TransStatusInquiryResponse(xmlns=name_space_string, msgResponseHeader=MsgResponseHeader(sndDt=null, msgTp=epcc.302.001.01, issrId=ICBC00001, drctn=21, signSn=87654321, ncrptnSn=, dgtlEnvlp=), msgResponseBody=MsgResponseBody(sysRtnInf=SysRtnInf(sysRtnCd=00000000, sysRtnDesc=, sysRtnTm=2020-11-29T15:41:15), bizInf=BizInf(rPFlg=foo, oriSysRtnCd=foo, oriSysRtnDesc=foo, oriBizstsCd=, oriBizStsDesc=, oriTrxctgy=0115, oriTrxId=20201128888888888888888800022, oriTrxStatus=foo, dbtrBankId=foo, cdtrBankId=foo, oriTrxAmt=foo, oriBatchId=foo, oriSgnNo=foo, pyerAcctTp=foo, pyerAcctId=foo, pyerAcctNm=foo, acctshrtId=foo, resfdAcctshrtId=foo)))

请求报文相关的类信息如下:

@Getter
@Setter
@ToString
@XStreamAlias("root") // 对应的XML中的标签名字
public class TransStatusInquiryRequest {

    @XStreamAlias("xmlns") // 对应的XML中的标签名字
    @XStreamAsAttribute // 声明root标签的属性
    private String xmlns;

    @XStreamAlias("MsgHeader") // 对应的XML中的标签名字
    private MsgRequestHeader msgRequestHeader;

    @XStreamAlias("MsgBody") // 对应的XML中的标签名字
    private MsgRequestBody msgRequestBody;
}

@Getter
@Setter
@ToString
@XStreamAlias("MsgHeader")
public class MsgRequestHeader {

    @XStreamAlias("SndDt")
    private String sndDt;

    @XStreamAlias("MsgTp")
    private String msgTp;

    @XStreamAlias("IssrId")
    private String issrId;

    @XStreamAlias("Drctn")
    private String drctn;

    @XStreamAlias("SignSN")
    private String signSn;

    @XStreamAlias("NcrptnSN")
    private String ncrptnSn;

    @XStreamAlias("DgtlEnvlp")
    private String dgtlEnvlp;
}

@Getter
@Setter
@ToString
@XStreamAlias("MsgBody")
public class MsgRequestBody {

    @XStreamAlias("InstgId")
    private String instgId;

    @XStreamAlias("RPFlg")
    private String rPFlg;

    @XStreamAlias("OriTrxInf")
    private OriginTrxInfo originTrxInfo;
}

@Getter
@Setter
@ToString
@XStreamAlias("OriTrxInf")
public class OriginTrxInfo {

    @XStreamAlias("OriTrxCtgy")
    private String oriTrxCtgy;

    @XStreamAlias("OriTrxId")
    private String oriTrxId;

    @XStreamAlias("OriTrxDtTm")
    private String oriTrxDtTm;

    @XStreamAlias("OriAcctTp")
    private String oriAcctTp;

    @XStreamAlias("OrisgnNo")
    private String orisgnNo;
}

响应报文对应的类信息如下:

@Getter
@Setter
@ToString
@XStreamAlias("root")
public class TransStatusInquiryResponse {
    // 对响应报文的校验可以使用Java Validation相关注解,非常方便
    @XStreamAlias("xmlns")
    @XStreamAsAttribute
    private String xmlns;

    @XStreamAlias("MsgHeader")
    private MsgResponseHeader msgResponseHeader;

    @XStreamAlias("MsgBody")
    private MsgResponseBody msgResponseBody;
}

@Getter
@Setter
@ToString
@XStreamAlias("MsgHeader")
public class MsgResponseHeader {

    @XStreamAlias("SndDt")
    private String sndDt;

    @XStreamAlias("MsgTp")
    private String msgTp;

    @XStreamAlias("IssrId")
    private String issrId;

    @XStreamAlias("Drctn")
    private String drctn;

    @XStreamAlias("SignSN")
    private String signSn;

    @XStreamAlias("NcrptnSN")
    private String ncrptnSn;

    @XStreamAlias("DgtlEnvlp")
    private String dgtlEnvlp;
}

@Getter
@Setter
@ToString
@XStreamAlias("MsgBody")
public class MsgResponseBody {

    @XStreamAlias("SysRtnInf")
    private SysRtnInf sysRtnInf;

    @XStreamAlias("BizInf")
    private BizInf bizInf;
}

@Getter
@Setter
@ToString
@XStreamAlias("SysRtnInf")
public class SysRtnInf {

    @XStreamAlias("SysRtnCd")
    private String sysRtnCd;

    @XStreamAlias("SysRtnDesc")
    private String sysRtnDesc;

    @XStreamAlias("SysRtnTm")
    private String sysRtnTm;
}

@Getter
@Setter
@ToString
@XStreamAlias("BizInf")
public class BizInf {

    @XStreamAlias("RPFlg")
    private String rPFlg;

    @XStreamAlias("OriSysRtnCd")
    private String oriSysRtnCd;

    @XStreamAlias("OriSysRtnDesc")
    private String oriSysRtnDesc;

    @XStreamAlias("OriBizstsCd")
    private String oriBizstsCd;

    @XStreamAlias("OriBizStsDesc")
    private String oriBizStsDesc;

    @XStreamAlias("OriTrxctgy")
    private String oriTrxctgy;

    @XStreamAlias("OriTrxId")
    private String oriTrxId;

    @XStreamAlias("OriTrxStatus")
    private String oriTrxStatus;

    @XStreamAlias("DbtrBankId")
    private String dbtrBankId;

    @XStreamAlias("CdtrBankId")
    private String cdtrBankId;

    @XStreamAlias("OriTrxAmt")
    private String oriTrxAmt;

    @XStreamAlias("OriBatchId")
    private String oriBatchId;

    @XStreamAlias("OriSgnNo")
    private String oriSgnNo;

    @XStreamAlias("PyerAcctTp")
    private String pyerAcctTp;

    @XStreamAlias("PyerAcctId")
    private String pyerAcctId;

    @XStreamAlias("PyerAcctNm")
    private String pyerAcctNm;

    @XStreamAlias("AcctshrtId")
    private String acctshrtId;

    @XStreamAlias("ResfdAcctshrtId")
    private String resfdAcctshrtId;
}

结束

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值