在现今的项目开发中,虽然数据的传输大部分都是用json格式来进行传输,但是xml毕竟也会有一些老的项目在进行使用,正常的老式方法是通过获取节点来进行一系列操作,个人感觉太过于复杂、繁琐。推荐一套简单的api--XStream类。在理解了原理的情况下看下注解的语法即会使用
例子是把xml映射成bean对象
<?xml version="1.0" encoding="UTF-8"?>
<c c1="0">
<d d1="101280101" d2="重庆" d3="nanping" d4="南坪"/>
<d d1="101280102" d2="重庆" d3="yubei" d4="渝北"/>
<d d1="101280103" d2="重庆" d3="dadukou" d4="大渡口"/>
</c>
第一种方法是使用 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的新特性,如:Annotation
、GenericType
等,需要在即将转换的JavaBean
中添加annotation
注解。
重要的使用有:
JAXBContext
类,是应用的入口,用于管理XML/Java绑定信息。Marshaller
接口,将Java对象序列化为XML数据。Unmarshaller
接口,将XML数据反序列化为Java对象。@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属性。
city的bean
package com.zoo.weixin.test.api.xstream;
import lombok.Data;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
/**
* @Author: xf
* @Date: 2019/3/26 17:42
* @Version 1.0
*/
@Data
//根元素
@XmlRootElement(name = "d")
//访问类型,通过字段
@XmlAccessorType(XmlAccessType.FIELD)
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 area;
}
CityList的bean
package com.zoo.weixin.test.api.xstream;
import lombok.Data;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;
/**
* @Author: xf
* @Date: 2019/3/26 17:43
* @Version 1.0
*/
@Data
@XmlRootElement(name = "c")
@XmlAccessorType(XmlAccessType.FIELD)
public class CityList {
@XmlElement(name = "d")
private List<City> cityList;
}
需要指定bean中的属性和xml的属性一一对应
需要有个工具类XmlBuilder
,主要是将XML转为指定的对象里面只需要一个方法
package com.zoo.weixin.test.api.xstream;
import com.thoughtworks.xstream.XStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import java.io.Reader;
import java.io.StringReader;
/**
* @Author: xf
* @Date: 2019/3/26 17:40
* @Version 1.0
*/
public class XmlBuilder {
/**
* JAXB将XML转为指定的POJO
*
* @param clazz
* @param xml
* @return
*/
public static Object JAXB_XmlToBean(Class<?> clazz, String xml) {
try {
Object xmlObject;
Reader reader;
JAXBContext context = JAXBContext.newInstance(clazz);
// XML 转为对象的接口
Unmarshaller unmarshaller = context.createUnmarshaller();
reader = new StringReader(xml);
//以文件流的方式传入这个string
xmlObject = unmarshaller.unmarshal(reader);
reader.close();
return xmlObject;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* XStream将XML转为指定的POJO
*
* @param clazz
* @param xml
* @return
*/
public static Object XStream_ToBean(Class<?> clazz, String xml) {
Object xmlObject;
XStream xstream = new XStream();
xstream.processAnnotations(clazz);
xstream.autodetectAnnotations(true);
xmlObject = xstream.fromXML(xml);
return xmlObject;
}
}
controller
package com.zoo.weixin.test.api;
import com.zoo.weixin.test.api.xstream.CityList;
import com.zoo.weixin.test.api.xstream.XmlBuilder;
import lombok.Cleanup;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
/**
* @Author: xf
* @Date: 2019/3/26 17:29
* @Version 1.0
*/
@RestController
public class XStreamController {
@RequestMapping("JAXB")
public CityList XStream(HttpServletRequest request, HttpServletResponse response) {
StringBuilder xml = new StringBuilder();
try {
@Cleanup ServletInputStream in = request.getInputStream();
// 将流转换为字符串
byte[] b = new byte[4096];
for (int n; (n = in.read(b)) != -1; ) {
xml.append(new String(b, 0, n, StandardCharsets.UTF_8));
}
// XML转为Java对象
CityList cityList = (CityList) XmlBuilder.JAXB_XmlToBean(CityList.class, xml.toString());
return cityList;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
第二种方法是使用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。
首先导入jar包
<!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream -->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.10</version>
</dependency>
City的bean
package com.zoo.weixin.test.api.xstream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import lombok.Data;
/**
* @Author: xf
* @Date: 2019/3/27 11:25
* @Version 1.0
*/
@Data
@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 area;
}
CityList的Bean
package com.zoo.weixin.test.api.xstream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import lombok.Data;
import java.util.List;
/**
* @Author: xf
* @Date: 2019/3/27 11:26
* @Version 1.0
*/
@Data
@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
转换器映射异常
同样也需要写个转换的工具类,工具类在上面那个工具类里
拓展了解
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实例,为线程安全的,可以供多个线程进行调用,共享使用。系统提供了多种标识解析器供我们选择,包括,DomDriver
、 JDomDriver
、StaxDriver
等等。
Xstream提供了对Json的支持,是因为Xstream内置了两个Driver:
1.JsonHierarchicalStreamDriver
:不依赖其他类库,只实现 obj->JSON
2.JettisonMappedXmlDriver
:依赖jettison
类库,实现 JSON->obj
or obj->JSON
两种Driver在处理相同设置的Object时会得到不同的JSON串,JsonHierarchicalStreamDriver
得到的串更简洁,确如官网所说。JsonHierarchicalStreamDriver
有个小问题——默认输出带格式的JSON
串,结构中带空格、换行,并且没有提供修饰方式。