前言

由于项目需要,调用第三方接口,接口返回格式为xml格式。遂用上了javax.xml 用于实现Bean和xml互转
首先我们看看工具类​​​XmlUtil​

/**
* XML转对象
*
* @param xmlStr xml字串
* @param t 对象类型
* @return 对象
*/
public static <T> T xmlToBean(String xmlStr, Class<T> t) {
try {
//特殊字符不让其转义,不然会报错
if (xmlStr.contains("&#xB;")) {
xmlStr = xmlStr.replace("&#xB;","<![CDATA[&#xB;]]>");
}
JAXBContext context = JAXBContext.newInstance(t);
Unmarshaller unmarshaller = context.createUnmarshaller();
StringReader reader = new StringReader(xmlStr);
SAXParserFactory sax = SAXParserFactory.newInstance();
//设置忽略命名空间
sax.setNamespaceAware(false);
XMLReader xmlReader = sax.newSAXParser().getXMLReader();
Source source = new SAXSource(xmlReader, new InputSource(reader));
return (T) unmarshaller.unmarshal(source);
} catch (JAXBException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
return null;
}

/**
* 对象转XML
*
* @param obj 对象
* @return 字符串
*/
public static String beanToXml(Object obj) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
JAXBContext context = JAXBContext.newInstance(obj.getClass());
Marshaller marshaller = context.createMarshaller();
// marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.FALSE);
marshaller.marshal(obj, out);
try {
return new String(out.toByteArray(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} catch (JAXBException e) {
e.printStackTrace();
}
return null;
}

代码解释


marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.FALSE);

如果为true的话,则不会生成​​<?xml version="1.0" encoding="UTF-8" standalone="yes"?>​

使用的Bean

@XmlRootElement(name = "requestXML")
@XmlAccessorType(XmlAccessType.FIELD)
public class TelefenCommonVO {
/**
* 应用编码
*/
@XmlElement(name = "AppID")
private String appid;
/**
* 接入业务
*/
private String SPID;
/**
* 请求流水
*/
private String RequestNo;
/**
* 请求时间
*/
private String RequestTime;
/**
* 签名
*/
@XmlTransient
private String Sign;

public String getAppid() {
return appid;
}

public void setAppid(String appid) {
this.appid = appid;
}

public String getSPID() {
return SPID;
}

public void setSPID(String SPID) {
this.SPID = SPID;
}

public String getRequestNo() {
return RequestNo;
}

public void setRequestNo(String requestNo) {
RequestNo = requestNo;
}

public String getRequestTime() {
return RequestTime;
}

public void setRequestTime(String requestTime) {
RequestTime = requestTime;
}

public String getSign() {
return Sign;
}

public void setSign(String sign) {
this.Sign = sign;
}

public TelefenCommonVO() {
}

protected TelefenCommonVO(Builder builder) {
this.appid = builder.AppID;
this.SPID = builder.SPID;
this.RequestNo = builder.RequestNo;
this.RequestTime = builder.RequestTime;
this.Sign = builder.Sign;
}
public static final class Builder{
/**
* 应用编码
*/
private String AppID;
/**
* 接入业务
*/
private String SPID;
/**
* 请求流水
*/
private String RequestNo;
/**
* 请求时间
*/
private String RequestTime;
/**
* 签名
*/
private String Sign;
public Builder setAppID(String appID) {
this.AppID = appID;
return this;
}
public Builder setSPID(String SPID){
this.SPID = SPID;
return this;
}
public Builder setRequestNo(String requestNo){
this.RequestNo = requestNo;
return this;
}
public Builder setRequestTime(String requestTime){
this.RequestTime = requestTime;
return this;
}
public Builder setSign(String sign){
this.Sign = sign;
return this;
}
public TelefenCommonVO build() {
return new TelefenCommonVO(this);
}
}
}

代码解释

  1. ​@XmlRootElement(name = "requestXML")​​ 注解是指定xml的根节点,作用在类上
  2. ​@XmlAccessorType​​​ 用于指定有java对象生成xml文件时对java对象属性的访问方式。 它的属性值是​​XmlAccessType​​的四个枚举值。分别是:
  • ​XmlAccessType.FIELD​​ java 对象中的所有成员变量
  • ​XmlAccessType.PROPERTY​​ java对象中所有通过getter/setter 方式访问的成员变量。
  • ​XmlAccessType.PUBLIC_MEMBER​​ java 对象中所有的public 访问权限的成员变量和通过getter/setter方式访问的成员变量 。
  • ​XmlAccessType.NONE​​ java对象的所有属性都不映射为XML元素
  1. ​@XmlElement​​ 该注解用在类的属性上。用于将属性映射为xml的子节点,可通过在后面配置name属性值类改变java属性在xml文件中的名称。例如:
@XmlElement(name = "AppID")
private String appid;

转化成xml为​​<AppID></AppID>​​​ 而不是​​<appid></appid>​​​ 5. ​​@XmlAccessorOrder​​ 用于对java 对象生成的xml元素进行排序。它有两个属性值:
 ​​AccessorOrder.ALPHABETICAL​​:对生成的xml元素按字母顺序排序;
 ​​XmlAccessOrder.UNDEFINED​​:不进行排序
6. ​​@XmlTransient​​ 用于标示在由java对象映射xml时,忽略此属性。即,在生成的xml文件中不出现此元素。
7. ​​@XmlElementWrapper​​ 在注解最外面再加一层,可用于POJO中包含List的属性中,例如:
待转化sql

<responseXML>
<Details>
<Detail>
<CardNo>11111</CardNo>
<CardPwd>2222</CardPwd>
<CodeURL/>
</Detail>
</Details>
</responseXML>

对应的Bean

@XmlRootElement(name ="responseXML")
@XmlAccessorType(XmlAccessType.FIELD)
public class OrderPayRespVO {

/**
* 卡信息列表
*/
@XmlElementWrapper(name="Details")
@XmlElement(name = "Detail")
private List<Detail> Details;
省略get,set方法
}
@XmlRootElement(name = "Detail")
@XmlAccessorType(XmlAccessType.FIELD)
public class Detail {
/**
* 卡号
*/
private String CardNo;
/**
* 卡密
*/
private String CardPwd;
/**
* 短链
*/
private String CodeURL;
省略get,set方法

}

转化之后

OrderPayRespVO{Details=[Detail{CardNo='11111', CardPwd='2222', CodeURL=''}]}
  1. 此外该Bean 还使用到了建造者设计模式来实现属性的链式调用。

测试代码

public static void main(String[] args) throws IOException {
TelefenCommonVO commonVO = new TelefenCommonVO.Builder()
.setAppID("1112")
.setRequestNo("3333")
.setSPID("444")
.setRequestTime("20180823")
.setSign("qqwqwqwq1121")
.build();

String xml = beanToXml(commonVO);
System.out.println("返回的xml为="+xml);
TelefenCommonVO commonVO1 = xmlToBean(xml, TelefenCommonVO.class);
System.out.println("转化后的bean为="+commonVO1.toString());


}

运行结果

返回的xml为=<?xml version="1.0" encoding="UTF-8" standalone="yes"?><requestXML><AppID>1112</AppID><SPID>444</SPID><RequestNo>3333</RequestNo><RequestTime>20180823</RequestTime></requestXML>
转化后的bean为=TelefenCommonVO{appid='1112', SPID='444', RequestNo='3333', RequestTime='20180823', Sign='null'}