一、前言
最近項目中遇到了一個這種需求:版本經理在上游環境通過配置XML的版本策略文件到我們系統,我們得解析XML的版本策略文件來看這些數據是否和我們系統后台的數據相一致,不一致的話,我們后台會去更新版本文件的數據,再通過定時調度把需要更新的版本文件推送給各個局點的設備進行升級。
通過這個需求,我們可以發現業界的XML與Java對象的互相轉換的是JAXB(Java Architecture for XML Binding) ,是一項可以根據XML Schema產生Java類的技術。該過程中,JAXB也提供了將XML實例文檔反向生成Java對象樹的方法,並能將Java對象樹的內容重新寫到XML實例文檔。從另一方面來講,JAXB提供了快速而簡便的方法將XML模式綁定到Java表示,從而使得Java開發者在Java應用程序中能方便地結合XML數據和處理函數。
二、什么是JAXB
1、JDK中JAXB相關的重要Class和Interface
JAXBContext類,是應用的入口,用於管理XML/Java綁定信息。
Marshaller接口,將Java對象序列化為XML數據。
Unmarshaller接口,將XML數據反序列化為Java對象。
2、JDK中JAXB相關的重要Annotation
@XmlType,將Java類或枚舉類型映射到XML模式類型
@XmlAccessorType(XmlAccessType.FIELD) ,控制字段或屬性的序列化。FIELD表示JAXB將自動綁定Java類中的每個非靜態的(static)、非瞬態的(由@XmlTransient標注)字段到XML。其他值還有XmlAccessType.PROPERTY和XmlAccessType.NONE。
@XmlAccessorOrder,控制JAXB 綁定類中屬性和字段的排序。
@XmlJavaTypeAdapter,使用定制的適配器(即擴展抽象類XmlAdapter並覆蓋marshal()和unmarshal()方法),以序列化Java類為XML。
@XmlElementWrapper ,對於數組或集合(即包含多個元素的成員變量),生成一個包裝該數組或集合的XML元素(稱為包裝器)。
@XmlRootElement,將Java類或枚舉類型映射到XML元素。
@XmlElement,將Java類的一個屬性映射到與屬性同名的一個XML元素。
@XmlAttribute,將Java類的一個屬性映射到與屬性同名的一個XML屬性。
在以上的注解中,用的最多的是@XMLType,@XmlAccessorType,@XmlRootElement。
使用JAXB的緣由:
1,在項目中,有時候會有很多的XML文件,但如果可以將這些文件通過對象的方式去操作,就會減少很多操作問題,而且更加符合程序員的編碼方式,
2,在項目中,有時候會遇到一個頁面中存在很多的實體類中的數據,而且有時候有些數據不是必需的,就是說可以通過DTO來編寫這些實體類,但有時候需要將這些DTO進行預先存儲,不是存儲到數據庫中,這樣就有兩種思路,可以存儲在內存中,也可以存儲在硬盤上,此時就可以通過將Java對象轉換成XML文件存儲,或者變成String類型進行存儲在內存中。
3,給出一個場景,比如說,一個頁面中有很多個模塊構成,但是這些模塊都是屬於一個整體的模塊,當用戶有操作其中幾個模塊的時候,但操作后的數據不是最終的數據,那這個時候首先要保存當前頁面中的數據(Done),然后到其他頁面進行其他操作后再轉到這個頁面,那么之前那個頁面中的數據應該還會存在,用戶可以方便查看。但是由於模塊較多,如果之前就存到數據庫中就會造成浪費,因為其不是最終的保存效果,而當用戶想進行保存(Save),此時才進行將最終的數據保存到數據庫中。在這個過程中就會用到大量的臨時數據,而解決這個問題很好的方法就是可以用XML保存頁面中當前的數據。
接下來我們就來看下項目中怎么進行Java對象和XML之間的相互轉換吧,當然我的寫得Demo的數據並不全是項目中的,這里舉幾個字段介紹,能讓小伙伴們快速上手就夠了。
三、Demo實戰
Policy.java 類,就是策略文件的信息,productGroup產品族是一個集合有多個產品。
package com.riemann.springbootdemo.model.objectConvertXML; import lombok.Data; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; import java.io.Serializable; import java.util.List; /** * @author riemann * @date 2019/08/29 22:10 */ @Data @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "Policy") //XML文件中的根標識 @XmlType(propOrder = { "productGroup", "sn", "updateUser", "updateLastDate", }) //控制JAXB 綁定類中屬性和字段的排序 public class Policy implements Serializable { private static final long serialVersionUID = 1L; // 產品族 private List<ProductGroup> productGroup; // sn號 private String sn; // 更新人員 private String updateUser; // 最后更新時間 private String updateLastDate; }
ProductGroup.java 類 產品族集合對應的產品與版本。
package com.riemann.springbootdemo.model.objectConvertXML; import lombok.Data; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; import java.io.Serializable; /** * @author riemann * @date 2019/08/29 22:14 */ @Data @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "ProductGroup") @XmlType(propOrder = { "product", "version", }) public class ProductGroup implements Serializable { private static final long serialVersionUID = 1L; // 產品 private String product; // 版本 private String version; }
此時給出最重要的進行Java對象和XML文件相互操作的核心代碼XMLUtil.java,其中有着兩種方式進行轉換,一種是轉換成對象和string類型的xml轉換,一種是對象和xml文件進行轉換。
XMLUtil.java
package com.riemann.springbootdemo.util; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import java.io.*; /** * 封裝了XML轉換成object,object轉換成XML的代碼 * * @author riemann * @date 2019/08/29 22:34 */ public class XMLUtil { /** * 將對象直接轉換成String類型的 XML輸出 * * @param obj * @return */ public static String convertToXml(Object obj) { // 創建輸出流 StringWriter sw = new StringWriter(); try { // 利用jdk中自帶的轉換類實現 JAXBContext context = JAXBContext.newInstance(obj.getClass()); Marshaller marshaller = context.createMarshaller(); // 格式化xml輸出的格式 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // 將對象轉換成輸出流形式的xml marshaller.marshal(obj, sw); } catch (JAXBException e) { e.printStackTrace(); } return sw.toString(); } /** * 將對象根據路徑轉換成xml文件 * * @param obj * @param path */ public static String convertToXml(Object obj, String path) { FileWriter fw = null; try { // 利用jdk中自帶的轉換類實現 JAXBContext context = JAXBContext.newInstance(obj.getClass()); Marshaller marshaller = context.createMarshaller(); // 格式化xml輸出的格式 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // 將對象轉換成輸出流形式的xml // 創建輸出流 fw = new FileWriter(path); marshaller.marshal(obj, fw); } catch (JAXBException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return fw.toString(); } /** * 將String類型的xml轉換成對象 * * @param clazz * @param xmlStr * @return */ public static Object convertXmlStrToObject(Class clazz, String xmlStr) { Object xmlObject = null; try { JAXBContext context = JAXBContext.newInstance(clazz); // 進行將Xml轉成對象的核心接口 Unmarshaller unmarshaller = context.createUnmarshaller(); StringReader sr = new StringReader(xmlStr); xmlObject = unmarshaller.unmarshal(sr); } catch (JAXBException e) { e.printStackTrace(); } return xmlObject; } /** * 將file類型的xml轉換成對象 * * @param clazz * @param xmlPath * @return */ public static Object convertXmlFileToObject(Class clazz, String xmlPath) { Object xmlObject = null; try { JAXBContext context = JAXBContext.newInstance(clazz); Unmarshaller unmarshaller = context.createUnmarshaller(); FileReader fr = null; fr = new FileReader(xmlPath); xmlObject = unmarshaller.unmarshal(fr); } catch (JAXBException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } return xmlObject; } }
ObjectConvertXMLController.java 控制器類
這里為了測試就不寫service以及impl類了哈,項目中還是要按照該有的模式去寫;這里我就在控制層測試。
package com.riemann.springbootdemo.controller; import com.riemann.springbootdemo.model.ApiResponse; import com.riemann.springbootdemo.model.ExportExcelData; import com.riemann.springbootdemo.model.objectConvertXML.Policy; import com.riemann.springbootdemo.service.impl.EmailTask; import com.riemann.springbootdemo.util.ConstantsUtil; import com.riemann.springbootdemo.util.XMLUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; /** * @author riemann * @date 2019/08/29 23:05 */ @RestController @RequestMapping(value = "/jaxb") public class ObjectConvertXMLController { private static final Logger logger = LoggerFactory.getLogger(ObjectConvertXMLController.class); @RequestMapping(value = "/objectToXML", method= RequestMethod.POST) public ApiResponse objectToXML(@RequestBody Policy policy) { String path = "D:\\Policy.xml"; logger.info("---將對象轉換成File類型的xml Start---"); String str = XMLUtil.convertToXml(policy, path); logger.info(str); logger.info("---將對象轉換成File類型的xml End---"); logger.info("---將File類型的xml轉換成對象 Start---"); Policy policyObj = (Policy) XMLUtil.convertXmlFileToObject(Policy.class, path); logger.info(policyObj.toString()); logger.info("---將File類型的xml轉換成對象 End---"); return new ApiResponse(ConstantsUtil.SUCCESS_CODE, null, ConstantsUtil.SUCCESS); } }
接下來我用postman模擬請求參數來請求
請求路徑:localhost:8080/jaxb/objectToXML
請求參數:
{ "productGroup": [ { "product":"AR", "version":"AR120" }, { "product":"AC", "version":"AC160" } ], "sn":"sn0001", "updateUser":"riemann", "updateLastDate":"2019-08-29 23:45:28" }
postman 返回結果:
IDEA 控制台返回結果:
2019-08-29 23:54:41.019 [http-nio-8080-exec-4] INFO c.r.s.controller.ObjectConvertXMLController----將對象轉換成File類型的xml Start--- 2019-08-29 23:54:41.028 [http-nio-8080-exec-4] INFO c.r.s.controller.ObjectConvertXMLController-java.io.FileWriter@2d11c0d8 2019-08-29 23:54:41.029 [http-nio-8080-exec-4] INFO c.r.s.controller.ObjectConvertXMLController----將對象轉換成File類型的xml End--- 2019-08-29 23:54:41.029 [http-nio-8080-exec-4] INFO c.r.s.controller.ObjectConvertXMLController----將File類型的xml轉換成對象 Start--- 2019-08-29 23:54:41.043 [http-nio-8080-exec-4] INFO c.r.s.controller.ObjectConvertXMLController-Policy(productGroup=[ProductGroup(product=AR, version=AR120), ProductGroup(product=AC, version=AC160)], sn=sn0001, updateUser=riemann, updateLastDate=2019-08-29 23:45:28) 2019-08-29 23:54:41.043 [http-nio-8080-exec-4] INFO c.r.s.controller.ObjectConvertXMLController----將File類型的xml轉換成對象 End---
D盤輸出結果:

Policy.xml 成功輸出
Policy.xml 策略文件請求也是一樣的

JAXB 已經將xml解析轉換成對象了,所以輸出結果還是一樣的。
2019-08-30 00:25:30.270 [http-nio-8080-exec-4] INFO c.r.s.controller.ObjectConvertXMLController----將對象轉換成File類型的xml Start--- 2019-08-30 00:25:30.280 [http-nio-8080-exec-4] INFO c.r.s.controller.ObjectConvertXMLController-java.io.FileWriter@4aa0cef6 2019-08-30 00:25:30.281 [http-nio-8080-exec-4] INFO c.r.s.controller.ObjectConvertXMLController----將對象轉換成File類型的xml End--- 2019-08-30 00:25:30.281 [http-nio-8080-exec-4] INFO c.r.s.controller.ObjectConvertXMLController----將File類型的xml轉換成對象 Start--- 2019-08-30 00:25:30.287 [http-nio-8080-exec-4] INFO c.r.s.controller.ObjectConvertXMLController-Policy(productGroup=[ProductGroup(product=AR, version=AR120), ProductGroup(product=AC, version=AC160)], sn=sn0001, updateUser=riemann, updateLastDate=2019-08-29 23:45:28) 2019-08-30 00:25:30.287 [http-nio-8080-exec-4] INFO c.r.s.controller.ObjectConvertXMLController----將File類型的xml轉換成對象 End---
