在現(xiàn)今的項(xiàng)目開發(fā)中闭树,雖然數(shù)據(jù)的傳輸大部分都是用json格式來進(jìn)行傳輸,但是xml畢竟也會(huì)有一些老的項(xiàng)目在進(jìn)行使用,正常的老式方法是通過獲取節(jié)點(diǎn)來進(jìn)行一系列操作基跑,個(gè)人感覺太過于復(fù)雜、繁瑣描焰。推薦一套簡(jiǎn)單的api--XStream類媳否。在理解了原理的情況下看下注解的語法即會(huì)使用
例子是把xml映射成bean對(duì)象
這個(gè)是要映射的xml代碼
<?xml version="1.0" encoding="UTF-8"?>
<c c1="0">
<d d1="101280101" d2="廣州" d3="guangzhou" d4="廣東"/>
<d d1="101280102" d2="番禺" d3="panyu" d4="廣東"/>
<d d1="101280103" d2="從化" d3="conghua" d4="廣東"/>
</c>
xml的代碼結(jié)構(gòu)很簡(jiǎn)單,可以看作是城市列表集合
城市的bean
@Data
@AllArgsConstructor
@NoArgsConstructor
public class City {
private String cityId;
private String cityName;
private String cityCode;
private String province;
這樣就與xml的d
元素中的屬性一一對(duì)應(yīng)了
然后再寫個(gè)城市列表的bean
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CityList {
private List<City> cityList;
}
以上的實(shí)體類bean
的set/get
方法都使用lombok
生成了
下面我們把xml代碼轉(zhuǎn)換成對(duì)象
第一種方法是使用 JAXB(Java Architecture for XML Binding) 實(shí)現(xiàn)XML與Bean的相互轉(zhuǎn)換
簡(jiǎn)介
JAXB是一個(gè)業(yè)界的標(biāo)準(zhǔn),是一項(xiàng)可以根據(jù)XML Schema
產(chǎn)生Java
類的技術(shù)荆秦。該過程中篱竭,JAXB也提供了將XML實(shí)例文檔反向生成Java
對(duì)象樹的方法,并能將Java
對(duì)象樹的內(nèi)容重新寫到 XML
實(shí)例文檔步绸。
Jaxb 2.0是JDK 1.6的組成部分掺逼。我們不需要下載第三方j(luò)ar包 即可做到輕松轉(zhuǎn)換。Jaxb2使用了JDK的新特性瓤介,如:Annotation
吕喘、GenericType
等赘那,需要在即將轉(zhuǎn)換的JavaBean
中添加annotation
注解。
重要的使用有:
JAXBContext
類氯质,是應(yīng)用的入口募舟,用于管理XML/Java綁定信息。
Marshaller
接口病梢,將Java對(duì)象序列化為XML數(shù)據(jù)胃珍。
Unmarshaller
接口,將XML數(shù)據(jù)反序列化為Java對(duì)象蜓陌。
@XmlType
觅彰,將Java類或枚舉類型映射到XML模式類型
@XmlAccessorType(XmlAccessType.FIELD)
,控制字段或?qū)傩缘男蛄谢?code>FIELD表示JAXB
將自動(dòng)綁定Java類中的每個(gè)非靜態(tài)的(static)钮热、非瞬態(tài)的(由@XmlTransient
標(biāo) 注)字段到XML填抬。其他值還有XmlAccessType
.PROPERTY
和XmlAccessType.NONE
。
@XmlAccessorOrder
隧期,控制JAXB 綁定類中屬性和字段的排序飒责。
@XmlJavaTypeAdapter
,使用定制的適配器(即擴(kuò)展抽象類XmlAdapter并覆蓋marshal()和unmarshal()方法)仆潮,以序列化Java類為XML宏蛉。
@XmlElementWrapper
,對(duì)于數(shù)組或集合(即包含多個(gè)元素的成員變量)性置,生成一個(gè)包裝該數(shù)組或集合的XML元素(稱為包裝器)拾并。
@XmlRootElement
,將Java類或枚舉類型映射到XML元素鹏浅。
@XmlElement
嗅义,將Java類的一個(gè)屬性映射到與屬性同名的一個(gè)XML元素。
@XmlAttribute
隐砸,將Java類的一個(gè)屬性映射到與屬性同名的一個(gè)XML屬性之碗。
具體使用
首先要在之前準(zhǔn)備好的bean上加上相關(guān)注解
城市Bean
//根元素
@XmlRootElement(name = "d")
//訪問類型,通過字段
@XmlAccessorType(XmlAccessType.FIELD)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class City {
@XmlAttribute(name = "d1")
private String cityId;
@XmlAttribute(name = "d2")
private String cityName;
@XmlAttribute(name = "d3")
private String cityCode;
@XmlAttribute(name = "d4")
private String province;
}
城市集合
@XmlRootElement(name = "c")
@XmlAccessorType
(XmlAccessType.FIELD)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CityList {
@XmlElement(name = "d")
private List<City> cityList;
}
需要指定bean中的屬性和xml的屬性一一對(duì)應(yīng)
需要有個(gè)工具類XmlBuilder
季希,主要是將XML轉(zhuǎn)為指定的對(duì)象
里面只需要一個(gè)方法
public class XmlBuilder {
/**
* 將XML轉(zhuǎn)為指定的POJO
* @param clazz
* @param xmlStr
* @return
* @throws Exception
*/
public static Object xmlStrToOject(Class<?> clazz, String xmlStr) throws Exception {
Object xmlObject = null;
Reader reader = null;
JAXBContext context = JAXBContext.newInstance(clazz);
// XML 轉(zhuǎn)為對(duì)象的接口
Unmarshaller unmarshaller = context.createUnmarshaller();
reader = new StringReader(xmlStr);
//以文件流的方式傳入這個(gè)string
xmlObject = unmarshaller.unmarshal(reader);
if (null != reader) {
reader.close();
}
return xmlObject;
}
}
這個(gè)方法有兩個(gè)參數(shù)Class<?> clazz
, String xmlStr
,Class<?> clazz
:指定我們需要轉(zhuǎn)換的對(duì)象褪那,xmlStr
:需要轉(zhuǎn)的xml字符串
轉(zhuǎn)換方法已經(jīng)寫好了,下面就來調(diào)用式塌,先讀取xml文件武通,再調(diào)用工具類的方法把XML轉(zhuǎn)為Java對(duì)象
public List<City> listCity() throws Exception {
// 讀取XML文件
Resource resource = new ClassPathResource("citylist.xml");
BufferedReader br = new BufferedReader(new InputStreamReader(resource.getInputStream(), "utf-8"));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = br.readLine()) !=null) {
buffer.append(line);
}
br.close();
// XML轉(zhuǎn)為Java對(duì)象
CityList cityList = (CityList)XmlBuilder.xmlStrToOject(CityList.class, buffer.toString());
return cityList.getCityList();
}
通過spring
提供的ClassPathResource
可以讀取,指定類路徑下的資源文件名稱就可以讀取到
下面需要使用 BufferedReader
把xml
讀取出來珊搀,把xml
中所有內(nèi)容都以讀取出來并寫入到buffer
字符串中.冶忱。
后面把需要需要轉(zhuǎn)的對(duì)象和讀取出來的內(nèi)容字符串傳入轉(zhuǎn)換方法就可以了
第二種方法是使用XStream
利用XStream在Java對(duì)象和XML之間相互轉(zhuǎn)換
簡(jiǎn)介
Xstream是一種OXMapping
技術(shù),是用來處理XML
文件序列化的框架,在將JavaBean
序列化境析,或?qū)?code>XML文件反序列化的時(shí)候囚枪,不需要其它輔助類和映射文件派诬,使得XML
序列化不再繁索。Xstream也可以將JavaBean
序列化成Json
或反序列化链沼,使用非常方便默赂。
主要使用
@XStreamAlias(“alis”)
java對(duì)象在xml中以標(biāo)簽的形式顯示時(shí),如果名字與類名或者屬性名不一致括勺,可以使用該標(biāo)簽并在括號(hào)內(nèi)注明別名缆八。
@XStreamOmitField
在輸出XML的時(shí)候忽略該屬性
@XStreamImplicit
如果該屬性是一個(gè)列表或者數(shù)組,在XML中不顯示list或者Array字樣
@XStreamAsAttribute
該屬性不單獨(dú)顯示成XML節(jié)點(diǎn)疾捍,而是作為屬性顯示出來
@XStreamContainedType
@XStreamConverter
設(shè)置轉(zhuǎn)換器
@XStreamConverters
converter主要用于將某些字段進(jìn)行復(fù)雜的轉(zhuǎn)換奈辰,轉(zhuǎn)換過程寫在一個(gè)類中。
然后將其注冊(cè)到XStream乱豆。
springboot使用XStream需要引入依賴
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.10</version>
</dependency>
然后在bean中加上相關(guān)注解
城市bean
@Data
@AllArgsConstructor
@NoArgsConstructor
@XStreamAlias("d")
public class City {
@XStreamAsAttribute
@XStreamAlias("d1")
private String cityId;
@XStreamAsAttribute
@XStreamAlias("d2")
private String cityName;
@XStreamAlias("d3")
@XStreamAsAttribute
private String cityCode;
@XStreamAsAttribute
@XStreamAlias("d4")
private String province;
}
城市集合bean
@Data
@AllArgsConstructor
@NoArgsConstructor
@XStreamAlias("c")
public class CityList {
@XStreamImplicit(itemFieldName="d")
private List<City> cityList;
}
重命名注解:@XStreamAlias()
省略集合根節(jié)點(diǎn):@XStreamImplicit
把字段節(jié)點(diǎn)設(shè)置成屬性:@XStreamAsAttribute
這些命名都需要和解析的xml的屬性名一一對(duì)應(yīng)奖恰,一旦不對(duì)應(yīng)就會(huì)報(bào)com.thoughtworks.xstream.mapper.CannotResolveClassException
異常,找不到對(duì)應(yīng)的類屬性
集合屬性的需要使用:@XStreamImplicit
,不然會(huì)報(bào)com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$DuplicateFieldException
轉(zhuǎn)換器映射異常
同樣也需要寫個(gè)轉(zhuǎn)換的工具類
public class XsteamUtil {
public static Object toBean(Class<?> clazz, String xml) {
Object xmlObject = null;
XStream xstream = new XStream();
xstream.processAnnotations(clazz);
xstream.autodetectAnnotations(true);
xmlObject= xstream.fromXML(xml);
return xmlObject;
}
}
傳參也是一樣宛裕,Class<?> clazz
:指定我們需要轉(zhuǎn)換的對(duì)象瑟啃,xml
:需要轉(zhuǎn)的xml字符串
這樣工具類就寫好了
拓展了解
XStream提供了很多方法供我們使用
autodetectAnnotations()
自動(dòng)檢測(cè)注解
processAnnotations()
應(yīng)用傳過來的類的注解
fromXML()
XML反序列化(JSON也是一樣)
toXML()
XML序列化(JSON也是一樣)
自定義解析器
Xstream序列化XML
,解析器用StaxDriver
指定解析器:XStream xstream = new XStream(new StaxDriver());
Xstream序列化Json
揩尸,解析器用JettisonMappedXmlDriver
指定解析器:XStream xstream = new XStream(new JettisonMappedXmlDriver());
也可以不具體指定解析器蛹屿,也是沒問題的
深入了解
XStreamxstream = new XStream();
默認(rèn)情況下,XStream
會(huì) 采用Xpp3
庫岩榆,XPP3
是一種運(yùn)行效率非常高的XML全解析實(shí)現(xiàn)蜡峰。如果你不想依靠Xpp3
庫的話,也可以使用一個(gè)標(biāo)準(zhǔn)的JAXP DOM
解析器朗恳,可以采用以下語句進(jìn)行初始化:
//不使用XPP3
庫
XStreamxstream = new XStream(new DomDriver());
此xstream實(shí)例,為線程安全的载绿,可以供多個(gè)線程進(jìn)行調(diào)用粥诫,共享使用。系統(tǒng)提供了多種標(biāo)識(shí)解析器供我們選擇崭庸,包括怀浆,DomDriver
、 JDomDriver
怕享、StaxDriver
等等执赡。
Xstream提供了對(duì)Json的支持,是因?yàn)閄stream內(nèi)置了兩個(gè)Driver:
1.JsonHierarchicalStreamDriver
:不依賴其他類庫函筋,只實(shí)現(xiàn) obj->JSON
2.JettisonMappedXmlDriver
:依賴jettison
類庫沙合,實(shí)現(xiàn) JSON->obj
or obj->JSON
兩種Driver在處理相同設(shè)置的Object時(shí)會(huì)得到不同的JSON串,JsonHierarchicalStreamDriver
得到的串更簡(jiǎn)潔跌帐,確如官網(wǎng)所說首懈。
JsonHierarchicalStreamDriver
有個(gè)小問題——默認(rèn)輸出帶格式的JSON
串绊率,結(jié)構(gòu)中帶空格、換行究履,并且沒有提供修飾方式滤否。