Springboot中使用Xstream進(jìn)行XML與Bean 相互轉(zhuǎn)換

在現(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í)體類beanset/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.PROPERTYXmlAccessType.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可以讀取,指定類路徑下的資源文件名稱就可以讀取到
下面需要使用 BufferedReaderxml讀取出來珊搀,把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í)解析器供我們選擇崭庸,包括怀浆,DomDriverJDomDriver怕享、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)中帶空格、換行究履,并且沒有提供修飾方式滤否。

總的來說,Xstream使用起來更簡(jiǎn)便最仑,代碼跟簡(jiǎn)單藐俺,也容易理解,對(duì)于xml和Json都提供了支持泥彤,不需要其它輔助類和映射文件欲芹,使得XML,Json序列化不再繁瑣全景,我推薦使用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末耀石,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子爸黄,更是在濱河造成了極大的恐慌滞伟,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炕贵,死亡現(xiàn)場(chǎng)離奇詭異梆奈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)称开,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門亩钟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鳖轰,你說我怎么就攤上這事清酥。” “怎么了蕴侣?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵焰轻,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我昆雀,道長(zhǎng)辱志,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任狞膘,我火速辦了婚禮揩懒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挽封。我一直安慰自己已球,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著和悦,像睡著了一般退疫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鸽素,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天褒繁,我揣著相機(jī)與錄音,去河邊找鬼馍忽。 笑死棒坏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的遭笋。 我是一名探鬼主播坝冕,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼瓦呼!你這毒婦竟也來了喂窟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤央串,失蹤者是張志新(化名)和其女友劉穎磨澡,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體质和,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡稳摄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了饲宿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厦酬。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖瘫想,靈堂內(nèi)的尸體忽然破棺而出仗阅,到底是詐尸還是另有隱情,我是刑警寧澤国夜,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布减噪,位于F島的核電站,受9級(jí)特大地震影響支竹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鸠按,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一礼搁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧目尖,春花似錦馒吴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豪治。三九已至,卻和暖如春扯罐,著一層夾襖步出監(jiān)牢的瞬間负拟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工歹河, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留掩浙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓秸歧,卻偏偏與公主長(zhǎng)得像厨姚,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子键菱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理谬墙,服務(wù)發(fā)現(xiàn),斷路器经备,智...
    卡卡羅2017閱讀 134,654評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,809評(píng)論 6 342
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架拭抬,建立于...
    Hsinwong閱讀 22,396評(píng)論 1 92
  • 小柳 離開故鄉(xiāng) 轉(zhuǎn)眼十五年 對(duì)那座城市 有著復(fù)雜的感情 人 是不會(huì)喜歡傷心之地的 在那里 有我太多的 痛徹心扉 從...
    小柳姐姐閱讀 236評(píng)論 0 0
  • 10天前,男友與我大吵了一架弄喘,因?yàn)槲以絹碓讲宦犓脑捑链淮┧I的衣服,不走他喜歡的風(fēng)格蘑志,不因?yàn)樗矚g有肉感的女生而...
    檸愛那個(gè)檬閱讀 407評(píng)論 0 1