Springboot中使用Xstream进行XML与Bean 相互转换-阿里云开发者社区

开发者社区> 开发与运维> 正文

Springboot中使用Xstream进行XML与Bean 相互转换

简介: 在现今的项目开发中,虽然数据的传输大部分都是用json格式来进行传输,但是xml毕竟也会有一些老的项目在进行使用,正常的老式方法是通过获取节点来进行一系列操作,个人感觉太过于复杂、繁琐。

在现今的项目开发中,虽然数据的传输大部分都是用json格式来进行传输,但是xml毕竟也会有一些老的项目在进行使用,正常的老式方法是通过获取节点来进行一系列操作,个人感觉太过于复杂、繁琐。推荐一套简单的api--XStream类。在理解了原理的情况下看下注解的语法即会使用
例子是把xml映射成bean对象

这个是要映射的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的代码结构很简单,可以看作是城市列表集合
城市的bean

@Data
@AllArgsConstructor
@NoArgsConstructor
public class City {
    private String cityId;
    private String cityName;
    private String cityCode;
    private String province;

这样就与xml的d元素中的属性一一对应了
然后再写个城市列表的bean

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CityList {
    private List<City> cityList;
}

以上的实体类beanset/get方法都使用lombok生成了

下面我们把xml代码转换成对象

第一种方法是使用 JAXB(Java Architecture for XML Binding) 实现XML与Bean的相互转换

简介

JAXB是一个业界的标准,是一项可以根据XML Schema产生Java类的技术。该过程中,JAXB也提供了将XML实例文档反向生成Java对象树的方法,并能将Java对象树的内容重新写到 XML实例文档。
Jaxb 2.0是JDK 1.6的组成部分。我们不需要下载第三方jar包 即可做到轻松转换。Jaxb2使用了JDK的新特性,如:AnnotationGenericType等,需要在即将转换的JavaBean中添加annotation注解。

重要的使用有:

JAXBContext类,是应用的入口,用于管理XML/Java绑定信息。
Marshaller接口,将Java对象序列化为XML数据。
Unmarshaller接口,将XML数据反序列化为Java对象。
@XmlType,将Java类或枚举类型映射到XML模式类型
@XmlAccessorType(XmlAccessType.FIELD) ,控制字段或属性的序列化。FIELD表示JAXB将自动绑定Java类中的每个非静态的(static)、非瞬态的(由@XmlTransient标 注)字段到XML。其他值还有XmlAccessType.PROPERTYXmlAccessType.NONE
@XmlAccessorOrder,控制JAXB 绑定类中属性和字段的排序。
@XmlJavaTypeAdapter,使用定制的适配器(即扩展抽象类XmlAdapter并覆盖marshal()和unmarshal()方法),以序列化Java类为XML。
@XmlElementWrapper ,对于数组或集合(即包含多个元素的成员变量),生成一个包装该数组或集合的XML元素(称为包装器)。
@XmlRootElement,将Java类或枚举类型映射到XML元素。
@XmlElement,将Java类的一个属性映射到与属性同名的一个XML元素。
@XmlAttribute,将Java类的一个属性映射到与属性同名的一个XML属性。

具体使用

首先要在之前准备好的bean上加上相关注解
城市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的属性一一对应

需要有个工具类XmlBuilder,主要是将XML转为指定的对象
里面只需要一个方法

public class XmlBuilder {
    /**
     * 将XML转为指定的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 转为对象的接口
        Unmarshaller unmarshaller = context.createUnmarshaller();
        reader = new StringReader(xmlStr);
        //以文件流的方式传入这个string
        xmlObject = unmarshaller.unmarshal(reader);
        if (null != reader) {
            reader.close();
        }
        return xmlObject;
    }
}

这个方法有两个参数Class<?> clazz, String xmlStr,Class<?> clazz:指定我们需要转换的对象,xmlStr:需要转的xml字符串

转换方法已经写好了,下面就来调用,先读取xml文件,再调用工具类的方法把XML转为Java对象

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转为Java对象
        CityList cityList = (CityList)XmlBuilder.xmlStrToOject(CityList.class, buffer.toString());
        return cityList.getCityList();
    }

通过spring提供的ClassPathResource可以读取,指定类路径下的资源文件名称就可以读取到
下面需要使用 BufferedReaderxml读取出来,把xml中所有内容都以读取出来并写入到buffer字符串中.。
后面把需要需要转的对象和读取出来的内容字符串传入转换方法就可以了

第二种方法是使用XStream

利用XStream在Java对象和XML之间相互转换
简介
Xstream是一种OXMapping 技术,是用来处理XML文件序列化的框架,在将JavaBean序列化,或将XML文件反序列化的时候,不需要其它辅助类和映射文件,使得XML序列化不再繁索。Xstream也可以将JavaBean序列化成Json或反序列化,使用非常方便。
主要使用
@XStreamAlias(“alis”)java对象在xml中以标签的形式显示时,如果名字与类名或者属性名不一致,可以使用该标签并在括号内注明别名。
@XStreamOmitField在输出XML的时候忽略该属性
@XStreamImplicit如果该属性是一个列表或者数组,在XML中不显示list或者Array字样
@XStreamAsAttribute该属性不单独显示成XML节点,而是作为属性显示出来
@XStreamContainedType
@XStreamConverter设置转换器
@XStreamConverters converter主要用于将某些字段进行复杂的转换,转换过程写在一个类中。
然后将其注册到XStream。

springboot使用XStream需要引入依赖

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.10</version>
</dependency>

然后在bean中加上相关注解
城市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()
省略集合根节点:@XStreamImplicit
把字段节点设置成属性:@XStreamAsAttribute

这些命名都需要和解析的xml的属性名一一对应,一旦不对应就会报com.thoughtworks.xstream.mapper.CannotResolveClassException异常,找不到对应的类属性
集合属性的需要使用:@XStreamImplicit,不然会报com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$DuplicateFieldException转换器映射异常

同样也需要写个转换的工具类

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:指定我们需要转换的对象,xml:需要转的xml字符串
这样工具类就写好了

拓展了解

XStream提供了很多方法供我们使用
autodetectAnnotations()自动检测注解
processAnnotations()应用传过来的类的注解
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();
默认情况下,XStream会 采用Xpp3库,XPP3是一种运行效率非常高的XML全解析实现。如果你不想依靠Xpp3库的话,也可以使用一个标准的JAXP DOM解析器,可以采用以下语句进行初始化:
//不使用XPP3
XStreamxstream = new XStream(new DomDriver());

此xstream实例,为线程安全的,可以供多个线程进行调用,共享使用。系统提供了多种标识解析器供我们选择,包括,DomDriverJDomDriverStaxDriver等等。

Xstream提供了对Json的支持,是因为Xstream内置了两个Driver:
1.JsonHierarchicalStreamDriver:不依赖其他类库,只实现 obj->JSON
2.JettisonMappedXmlDriver:依赖jettison类库,实现 JSON->obj or obj->JSON
两种Driver在处理相同设置的Object时会得到不同的JSON串,JsonHierarchicalStreamDriver得到的串更简洁,确如官网所说。
JsonHierarchicalStreamDriver有个小问题——默认输出带格式的JSON串,结构中带空格、换行,并且没有提供修饰方式。

总的来说,Xstream使用起来更简便,代码跟简单,也容易理解,对于xml和Json都提供了支持,不需要其它辅助类和映射文件,使得XML,Json序列化不再繁琐,我推荐使用

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章