Java解析XML的类库很多,本文记录用XStream库对XML的处理
背景
实际开发中,应用报文的格式一般都是JSON和XML;JSON大家都很熟悉(优秀类库:GSON/FastJson/Jackson),但对XML的解析可能并不熟悉,这主要是因为XML一般用于特定的领域:如金融和支付行业等等,想要和银联、网联对接,XML是少不了的
XStream的使用
XStream是解析XML的一款轻量级类库,简单快捷。下面以某银行的交易查询接口为例,讲解XStream对XML的序列化和反序列化的相关使用方法:
报文结构如下:
xml报文结构.png
-
创建对应的类(具体类信息添加在文末)
xml对应的model.png 创建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());
}
}
}
- 测试序列化和反序列化的结果
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, 回聊~