目录
xstream
XStream是一个Java类库,主要用于将对象序列化为XML(或JSON)或将XML(或JSON)反序列化为对象。XStream使用Java反射机制对要进行序列化的对象树的结构进行探索,无需对对象进行修改。它可以序列化内部字段,包括私有(private)和最终(final)字段,并支持非公开类以及内部类。在缺省情况下,XStream不需要配置映射关系,对象和字段将映射为同名XML元素。
优点:
- 易用性:XStream不需要额外的辅助类或映射文件,使得XML序列化不再繁琐。
- 灵活性:支持多种数据类型转换,包括用户自定义的类型转换器。
- 可读性:输出通常比其他工具更清晰和易于阅读。
缺点:
- 效率:相对于某些工具(如XMLEncoder),XStream在处理大型数据集时可能会较慢,因为它需要在每个对象实例上运行解析器。
- 内存使用:XStream使用流操作可能导致较高的内存使用,特别是在处理大型数据集时。
XStream的应用场景
XStream的常见用途包括对象传输、持久化、配置以及单元测试等。它在许多项目中,特别是在支付API对接时,被用于实现Java对象和XML文档的互转。
用到的依赖
XML
<!--XML解析-->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.20</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
代码实现
XML
<!--xml报文-->
<?xml version='1.0' encoding='UTF-8'?>
<Package>
<Header>
<RequestType>131</RequestType>
<SystemNo>001</SystemNo>
<SendTime>2024-06-05 09:53:38</SendTime>
<Status>100</Status>
<ErrorMessage />
</Header>
<Sign>NgJzJyhoeXYd/TJvJitByhUR1UVMJ+FjuMl4WVBjP0CsOM6owyX9nCn1c/IL+OpVeSYkl4k60Du8nLa13wRB1oqFA8I2zel9+Xiq7lAL0otIcdww4F9i5uULk2wpq8ApXcghO5suL54FPOutc+2gWNUUmdP6fb2/L2RFKOlcBig=</Sign>
<Response>
<DepartmentCode>5</DepartmentCode>
<TransSourceCode>0</TransSourceCode>
<PayNo />
<PayAmount>100</PayAmount>
<RealPayAmount>100</RealPayAmount>
<PaymentTime>2024-06-05 09:50:49</PaymentTime>
<DealTime>2024-06-05 09:50:49</DealTime>
<PayType>1</PayType>
<PlatformCode>35</PlatformCode>
<PlatformName />
<OrderId>1000000001678451</OrderId>
<OrderStatus>2</OrderStatus>
<PageUrl>https://blog.csdn.net/weixin_59383491?type=blog</PageUrl>
<NotifyUrl>https://blog.csdn.net/weixin_59383491?type=blog</NotifyUrl>
<AutoErrMsg />
<BusinessTypeDetail />
<BusinessType />
<TradeList>
<TradeIfo>
<ProductId />
<ApplyPolicyNo />
<PersonnelName />
<PlanCode />
<ProductName>一百减一是零</ProductName>
<BatchDetailNo>1010000202400000065</BatchDetailNo>
<ProductType>7</ProductType>
<BatchPolicyNo />
<TradeDetailNo />
<TradeAmt>100</TradeAmt>
<OriginCode />
<OriginTradeNo />
</TradeIfo>
</TradeList>
</Response>
</Package>
xml标签对应的实体类
Header
java
package com.yun.greedy.modules.util.xstream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
@XStreamAlias("Header")
@Data
public class Header {
@XStreamAlias("RequestType")
private String requestType;
@XStreamAlias("SystemNo")
private String systemNo;
@XStreamAlias("SendTime")
private String sendTime;
@XStreamAlias("Status")
private String status;
@XStreamAlias("ErrorMessage")
private String errorMessage;
}
Package
java
package com.yun.greedy.modules.util.xstream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
@XStreamAlias("Package")
@Data
public class Package {
@XStreamAlias("Header")
private Header head;
@XStreamAlias("Sign")
private String sign;
@XStreamAlias("Request")
private Request request;
@XStreamAlias("Response")
private Response response;
}
Request
java
package com.yun.greedy.modules.util.xstream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
import java.util.List;
@Data
@XStreamAlias("Request")
public class Request {
@XStreamAlias("DepartmentCode")
private String departmentCode;
@XStreamAlias("TransSourceCode")
private String transSourceCode;
@XStreamAlias("PayType")
private String payType;
@XStreamAlias("PlatformCode")
private String platformCode;
@XStreamAlias("BankType")
private String bankType;
@XStreamAlias("PayAmount")
private String payAmount;
@XStreamAlias("PageUrl")
private String pageUrl;
@XStreamAlias("NotifyUrl")
private String notifyUrl;
@XStreamAlias("TradeNo")
private String tradeNo;
@XStreamAlias("TradeList")
private List<TradeInfo> tradeList;
}
Response
java
package com.yun.greedy.modules.util.xstream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
import java.util.List;
@Data
@XStreamAlias("Response")
public class Response {
@XStreamAlias("DepartmentCode")
private String departmentCode;
@XStreamAlias("TransSourceCode")
private String transSourceCode;
@XStreamAlias("PayAmount")
private String payAmount;
@XStreamAlias("RealPayAmount")
private String realPayAmount;
@XStreamAlias("PaymentTime")
private String paymentTime;
@XStreamAlias("PayType")
private String payType;
@XStreamAlias("PlatformCode")
private String platformCode;
@XStreamAlias("PlatformName")
private String platformName;
@XStreamAlias("TradeNo")
private String tradeNo;
@XStreamAlias("OrderId")
private String orderId;
@XStreamAlias("OrderStatus")
private String orderStatus;
@XStreamAlias("PageUrl")
private String pageUrl;
@XStreamAlias("NotifyUrl")
private String notifyUrl;
@XStreamAlias("AutoErrMsg")
private String autoErrMsg;
@XStreamAlias("DealTime")
private String dealTime;
@XStreamAlias("PayNo")
private String payNo;
@XStreamAlias("BusinessTypeDetail")
private String businessTypeDetail;
@XStreamAlias("BusinessType")
private String businessType;
@XStreamAlias("TradeList")
private List<TradeInfo> tradeList;
}
TradeInfo
java
package com.yun.greedy.modules.util.xstream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
@Data
@XStreamAlias("TradeIfo")
public class TradeInfo {
@XStreamAlias("ProductId")
private String productId;
@XStreamAlias("ApplyPolicyNo")
private String applyPolicyNo;
@XStreamAlias("PlanCode")
private String planCode;
@XStreamAlias("BatchPolicyNo")
private String batchPolicyNo;
@XStreamAlias("BatchDetailNo")
private String batchDetailNo;
@XStreamAlias("TradeDetailNo")
private String tradeDetailNo;
@XStreamAlias("PersonnelName")
private String personnelName;
@XStreamAlias("CertificateNo")
private String certificateNo;
@XStreamAlias("MobileTelephone")
private String mobileTelephone;
@XStreamAlias("TradeAmt")
private String tradeAmt;
@XStreamAlias("ProductType")
private String productType;
@XStreamAlias("ProductName")
private String productName;
@XStreamAlias("ViewProductUrl")
private String viewProductUrl;
@XStreamAlias("TradeCount")
private String tradeCount;
@XStreamAlias("InsuranceBeginTime")
private String insuranceBeginTime;
@XStreamAlias("OriginCode")
private String originCode;
@XStreamAlias("OriginTradeNo")
private String originTradeNo;
}
工具类
XmlUtils
java
package com.yun.greedy.modules.util;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.Dom4JDriver;
import com.thoughtworks.xstream.security.AnyTypePermission;
import com.yun.greedy.modules.util.xstream.Package;
import com.yun.greedy.modules.util.xstream.*;
import org.dom4j.DocumentFactory;
import org.dom4j.io.OutputFormat;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class XmlUtils {
/*
* 将XML报文转化为java对象
*/
public static Object makeObjectFromXml(String docStr, Class[] classList) {
XStream xstream = new XStream(new Dom4JDriver());
//由于对象默认开启安全防护,尽量限制最低权限
xstream.addPermission(AnyTypePermission.ANY);
xstream.processAnnotations(classList);
return xstream.fromXML(docStr);
}
/**
* 将对象转化为xml报文
*
* @param object
* @param b 是否显示为空的节点
* @return
*/
public static String objectToXml(Object object, boolean b) {
if (b) {
replaceNullValue(object);
}
OutputFormat outputFormat = new OutputFormat();
outputFormat.setEncoding("UTF-8");
outputFormat.setNewLineAfterDeclaration(false);//对象名称是否显示路径
// outputFormat.setIndent(" ");
outputFormat.setNewlines(true);//XML节点换行
XStream xstream = new XStream(new Dom4JDriver(new DocumentFactory(), outputFormat));
xstream.autodetectAnnotations(true);
return xstream.toXML(object);
}
/**
* changeFiledValue(替换字符串为null值的情况)
*
* @param obj
* @return void
*/
private static void replaceNullValue(Object obj) {
if (obj == null) {
return;
}
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
try {
String type = field.getType().getName();
field.setAccessible(true);
Object value = field.get(obj);
if ("java.lang.String".equals(type)) {
String genericStr = field.toGenericString();
if (!genericStr.contains("final")) {
field.set(obj, (value == null ? "" : value));
}
} else if ("java.util.List".equals(type)) {
List list = (List) value;
if (list != null && list.size() > 0) {
for (int i = 0; i < list.size(); i++) {
Object subObj = list.get(i);
replaceNullValue(subObj);
}
}
} else {
replaceNullValue(value);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
System.out.println("返回报文对象替换null值出错:" + e.getMessage());
} catch (IllegalAccessException e) {
e.printStackTrace();
System.out.println("返回报文对象替换null值出错:" + e.getMessage());
}
}
}
public static void main(String[] args) {
String strXML = "<?xml version='1.0' encoding='UTF-8'?>\n" +
"<Package>\n" +
" <Header>\n" +
" <RequestType>131</RequestType>\n" +
" <SystemNo>001</SystemNo>\n" +
" <SendTime>2024-06-05 09:53:38</SendTime>\n" +
" <Status>100</Status>\n" +
" <ErrorMessage />\n" +
" </Header>\n" +
" <Sign>NgJzJyhoeXYd/TJvJitByhUR1UVMJ+FjuMl4WVBjP0CsOM6owyX9nCn1c/IL+OpVeSYkl4k60Du8nLa13wRB1oqFA8I2zel9+Xiq7lAL0otIcdww4F9i5uULk2wpq8ApXcghO5suL54FPOutc+2gWNUUmdP6fb2/L2RFKOlcBig=</Sign>\n" +
" <Response>\n" +
" <DepartmentCode>5</DepartmentCode>\n" +
" <TransSourceCode>0</TransSourceCode>\n" +
" <PayNo />\n" +
" <PayAmount>100</PayAmount>\n" +
" <RealPayAmount>100</RealPayAmount>\n" +
" <PaymentTime>2024-06-05 09:50:49</PaymentTime>\n" +
" <DealTime>2024-06-05 09:50:49</DealTime>\n" +
" <PayType>1</PayType>\n" +
" <PlatformCode>35</PlatformCode>\n" +
" <PlatformName />\n" +
" <OrderId>1000000001678451</OrderId>\n" +
" <OrderStatus>2</OrderStatus>\n" +
" <PageUrl>https://blog.csdn.net/weixin_59383491?type=blog</PageUrl>\n" +
" <NotifyUrl>https://blog.csdn.net/weixin_59383491?type=blog</NotifyUrl>\n" +
" <AutoErrMsg />\n" +
" <BusinessTypeDetail />\n" +
" <BusinessType />\n" +
" <TradeList>\n" +
" <TradeIfo>\n" +
" <ProductId />\n" +
" <ApplyPolicyNo />\n" +
" <PersonnelName />\n" +
" <PlanCode />\n" +
" <ProductName>一百减一是零</ProductName>\n" +
" <BatchDetailNo>1010000202400000065</BatchDetailNo>\n" +
" <ProductType>7</ProductType>\n" +
" <BatchPolicyNo />\n" +
" <TradeDetailNo />\n" +
" <TradeAmt>100</TradeAmt>\n" +
" <OriginCode />\n" +
" <OriginTradeNo />\n" +
" </TradeIfo>\n" +
" </TradeList>\n" +
" </Response>\n" +
"</Package>";
Class[] classes = {Package.class, Header.class, Response.class, TradeInfo.class};
Package packageObj = (Package) XmlUtils.makeObjectFromXml(strXML, classes);
String str = null != packageObj ?
"XML解析成功!" + packageObj.toString() : "报文解析失败!";
System.out.println("========XML转对象========");
System.out.println(str);
Request re = new Request();
re.setDepartmentCode("123");
re.setTransSourceCode("TS");
re.setBankType("CS");
re.setPageUrl("https://blog.csdn.net/weixin_59383491?type=blog");
TradeInfo tradeInfo = new TradeInfo();
tradeInfo.setPersonnelName("一百减一是零");
tradeInfo.setViewProductUrl("https://blog.csdn.net/weixin_59383491?type=blog");
TradeInfo tradeInfo2 = new TradeInfo();
tradeInfo2.setPersonnelName("一百减一是零");
tradeInfo2.setViewProductUrl("https://blog.csdn.net/weixin_59383491?type=blog");
List<TradeInfo> tradeInfoList = new ArrayList<>();
tradeInfoList.add(tradeInfo);
tradeInfoList.add(tradeInfo2);
re.setTradeList(tradeInfoList);
System.out.println("========对象转XML========");
String s = XmlUtils.objectToXml(re, false);
System.out.println(s);
}
}