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

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

背景

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

XStream的使用

XStream是解析XML的一款轻量级类库,简单快捷。下面以某银行的交易查询接口为例,讲解XStream对XML的序列化和反序列化的相关使用方法:

报文结构如下:

xml报文结构.png

  1. 创建对应的类(具体类信息添加在文末)


    xml对应的model.png
  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 
     * @return 目标类对象
     */
    public static  T fromXml(InputStream is, Class 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 = "\n" +
            "  \n" +
            "    epcc.302.001.01\n" +
            "    ICBC00001\n" +
            "    21\n" +
            "    87654321\n" +
            "    \n" +
            "    \n" +
            "  \n" +
            "  \n" +
            "    \n" +
            "      00000000\n" +
            "      \n" +
            "      2020-11-29T15:41:15\n" +
            "    \n" +
            "    \n" +
            "      foo\n" +
            "      foo\n" +
            "      foo\n" +
            "      \n" +
            "      \n" +
            "      0115\n" +
            "      20201128888888888888888800022\n" +
            "      foo\n" +
            "      foo\n" +
            "      foo\n" +
            "      foo\n" +
            "      foo\n" +
            "      foo\n" +
            "      foo\n" +
            "      foo\n" +
            "      foo\n" +
            "      foo\n" +
            "      foo\n" +
            "    \n" +
            "  \n" +
            "";

    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;
    }
}

结果如下:

序列化,组装交易查询的请求报文:

  
    2020-11-29T15:46:55
    epcc.301.001.01
    ICBC00001
    11
    12345678
    
    
  
  
    12345678901234
    2
    
      0115
      20201128888888888888888800022
      2020-11-29T15:46:55
      00
      
    
  


--------------------------
反序列化响应报文,结果如下:
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;
}

OK, 回聊~

你可能感兴趣的:(掌握Java XML解析: 序列化 反序列化)