使用JAXB包实现bean和xml的互转
前言
由于项目需要,调用第三方接口,接口返回格式为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("")) {
xmlStr = xmlStr.replace("","<![CDATA[]]>");
}
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);
}
}
}
代码解释
@XmlRootElement(name = "requestXML") 注解是指定xml的根节点,作用在类上
@XmlAccessorType 用于指定有java对象生成xml文件时对java对象属性的访问方式。 它的属性值是XmlAccessType的四个枚举值。分别是:
XmlAccessType.FIELD java 对象中的所有成员变量
XmlAccessType.PROPERTY java对象中所有通过getter/setter 方式访问的成员变量。
XmlAccessType.PUBLIC_MEMBER java 对象中所有的public 访问权限的成员变量和通过getter/setter方式访问的成员变量 。
XmlAccessType.NONE java对象的所有属性都不映射为XML元素
@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=''}]}
此外该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'}
作者:码农飞哥
微信公众号:码农飞哥