最近几天,我自己负责的应用这边引入了一个新的合作方,主要是我这边调用他们的接口,但是有个很坑的地方,他们传参居然不支持json格式,并且只支持xml格式进行交互,于是自己写了一个工具类去支持bean与xml互相转换,json与xml之间互相转换。

JAXBContext 接口

我在这里使用了rt.jar 下javax下的 JAXBContext 接口,它提供了 JAXB API 的客户端入口点。它提供了管理实现 JAXB 绑定框架操作所需的 XML/Java 绑定信息的抽象。

  • 获取 JAXBContext 接口实例
    JAXBContext 接口为我们提供了获取 JAXBContext 实例的 newInstance 方法。将需要转换为xml的bean的class传入即可。
JAXBContext context = JAXBContext.newInstance(zlass);
 

Marshaller 接口

  • 获取 Marshaller 接口实例
    JAXBContext 实例为我们提供了获取 Marshaller 实例的 createMarshaller方法。
Marshaller marshaller = context.createMarshaller();
 

Marshaller 接口主要是将java对象序列化成xml字符串,是通过 marshal 方法。

/**
* JAVA bean 转 xml
* @param obj
* @param zlass
* @return
* @throws JAXBException
*/
public static String beanToXml (Object obj, Class<?> zlass) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(zlass);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "GBK");
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
StringWriter writer = new StringWriter();
marshaller.marshal(obj,writer);
return writer.toString();
}
 

Marshaller 接口中还定义了5个属性,分别是:

  • JAXB_ENCODING
    这个属性是设置编码集,
marshaller.setProperty(Marshaller.JAXB_ENCODING, "GBK"); 
  • JAXB_FORMATTED_OUTPUT
    这个属性是是否格式化生成的xml串 true-格式化,false-不格式化
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
  • JAXB_SCHEMA_LOCATION
    指定xsi:schemaLocation,它定义了XML Namespace和对应的XSD(Xml Schema Definition)文档的位置的关系。它的值由一个或多个URI引用对组成,两个URI之间以空白符分隔(空格和换行均可)。第一个URI是定义的XML Namespace的值,第二个URI给出Schema文档的位置,Schema处理器将从这个位置读取Schema文档,该文档的targetNamespace必须与第一个URI相匹配。
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "xxx.xxx.xxx"); 
  • JAXB_NO_NAMESPACE_SCHEMA_LOCATION
    如果没有Namespeace,但是需要使用Schema,就需要用到JAXB_NO_NAMESPACE_SCHEMA_LOCATION,它可以指定将放置在已编组 XML 输出中的 xsi:noNamespaceSchemaLocation 属性值
marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "xxx.xxx.xxx"); 
  • JAXB_FRAGMENT
    是否省略xml头信息()true-省略,false-不省略
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false); 

Unmarshaller 接口

  • 获取 Unmarshaller 接口实例
    JAXBContext 实例为我们提供了获取 Unmarshaller 实例的 createUnmarshaller 方法,需要注意的是,反序列化时需要将转换的bean上加上无参构造器。
Unmarshaller unmarshaller = context.createUnmarshaller(); 

Marshaller 接口主要是将java对象序列化成xml字符串,是通过 unmarshal 方法。

/**
* xml 转 JAVA bean
* @param xml
* @param zlass
* @return
* @throws JAXBException
*/
public static Object xmlToBean (String xml, Class<?> zlass) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(zlass);
Unmarshaller unmarshaller = context.createUnmarshaller();
Object object = unmarshaller.unmarshal(new StringReader(xml));
return object;

JAXB相关的重要Annotation

我在这定义3个类,来简单说一下下面几个常用的注解的作用,与用法。
首先是一个班级类

@XmlRootElement(name = "class")
public class ClassAndGrade { private ClassAndGradeMsg classAndGrade; private List<Student> students; @XmlElement(name="classAndGrade")
public ClassAndGradeMsg getClassAndGrade() {
return classAndGrade;
} public void setClassAndGrade(ClassAndGradeMsg classAndGrade) {
this.classAndGrade = classAndGrade;
} @XmlElementWrapper(name="students")
@XmlElement(name="student")
public List<Student> getStudents() {
return students;
} public void setStudents(List<Student> students) {
this.students = students;
} } 

然后再定义一个班级信息类

public class ClassAndGradeMsg {

    private Integer personNum;

    private String name;

    private String classTeacher;

    /**
* @Title:ClassAndGradeMsg
* @param:@param personNum
* @param:@param name
* @param:@param classTeacher
* @throws
*/
public ClassAndGradeMsg(Integer personNum, String name, String classTeacher) {
super();
this.personNum = personNum;
this.name = name;
this.classTeacher = classTeacher;
} @XmlElement(name="personNum")
public Integer getPersonNum() {
return personNum;
} public void setPersonNum(Integer personNum) {
this.personNum = personNum;
} @XmlElement(name="name")
public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @XmlElement(name="classTeacher")
public String getClassTeacher() {
return classTeacher;
} public void setClassTeacher(String classTeacher) {
this.classTeacher = classTeacher;
}

再定义以后学生类

public class Student {

    private String name;

    private Integer age;

    private String sex;

    /**
* @Title:Student
* @param:@param name
* @param:@param age
* @param:@param sex
* @throws
*/
public Student(String name, Integer age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
} @XmlElement(name="name")
public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @XmlElement(name="age")
public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} @XmlElement(name="sex")
public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} } 

最后再写一个测试main方法

public static void main(String[] args) throws ClassNotFoundException {
ClassAndGrade classAndGrade = new ClassAndGrade();
ClassAndGradeMsg classAndGradeMsg = new ClassAndGradeMsg(, "三年二班", "张三");
classAndGrade.setClassAndGrade(classAndGradeMsg);
List<Student> list = new ArrayList<Student>();
Student s1 = new Student("李四", , "男");
Student s2 = new Student("王五", , "女");
list.add(s1);
list.add(s2);
classAndGrade.setStudents(list);
try {
String xml = XmlUtil.beanToXml(classAndGrade, ClassAndGrade.class);
System.out.println(xml);
} catch (Exception e) {
e.printStackTrace();
}
  • @XmlRootElement
    类级别的注解,这个注解为根节点的注解,加在类上面,而且为必要的注解,如果没有此注解,执行beanToXml方法时将会报异常。这个根节点默认名字为类名,但是可以设置name属性来修改根节点名字。namespace属性可以用于指定生成的元素所属的命名空间。
@XmlRootElement(name = "class")
public class ClassAndGrade { 

执行结果如下,ClassAndGrade 被修改为class:

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<class>
<classAndGrade>
<classTeacher>张三</classTeacher>
<name>三年二班</name>
<personNum></personNum>
</classAndGrade>
<students>
<student>
<age></age>
<name>李四</name>
<sex>男</sex>
</student>
<student>
<age></age>
<name>王五</name>
<sex>女</sex>
</student>
</students>
</class> 
  • @XmlElement
    字段,方法级别的注解,将java类的属性映射为xml的一个结点。一般使用在属性上,或者get方法上,其中常用的属性有name、nillable、namespace、defaultValue。name可以设置结点的名称;nillable 指定文本是否可以为空,true-可以为空,false-不可以为空,默认为false,如果设置为true,则该字段为空是,这个结点也会生成,但是值为空,如果是指为false,则该结点不生成;namespace属性可以用于指定生成的元素所属的命名空间;defaultValue 可以设置该结点的默认文本。
@XmlElement(name="sex", nillable = false, defaultValue = "女")
public String getSex() {
return sex;
  • @XmlTransient
    类,字段,方法级别的注解。当添加这个注解后,这个属性或者类将不进行映射。需要注意的是该注解与所有其他JAXB注解相互排斥.
    
@XmlTransient
public Integer getAge() {
return age;

现在执行结果如下:

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<classAndGrade>
<classAndGradeMsg>
<classTeacher>张三</classTeacher>
<name>三年二班</name>
<personNum></personNum>
</classAndGradeMsg>
<students>
<student>
<name>李四</name>
<sex>男</sex>
</student>
<student>
<name>王五</name>
<sex>女</sex>
</student>
</students>
</classAndGrade> 

age结点被剔除

  • @XmlAccessorType
    类级别注解,其中有一个value属性,值为XmlAccessType的枚举类。
  1. XmlAccessType.PROPERTY 加这个value表示,会将所有拥有get方法和set方法的属性(必须2个方法都有,否则不映射)映射成xml,除非加入@XmlTransient则不会映射,如果没有get/set方法,则需要再属性上加上@XmlElement。
@XmlAccessorType(value = XmlAccessType.PROPERTY)
public class Student { private String name;
private Integer age;
@XmlElement(name="sex", nillable = false, defaultValue = "女")
private String sex; /**
* @Title:Student
* @param:@param name
* @param:@param age
* @param:@param sex
* @throws
*/
public Student(String name, Integer age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
}

我在Student类中加上@XmlAccessorType注解,并且在sex属性上加上@XmlElement注解,给name属性加上get/set方法,给age只加了get方法,执行结果如下:

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<classAndGrade>
<classAndGradeMsg>
<classTeacher>张三</classTeacher>
<name>三年二班</name>
<personNum></personNum>
</classAndGradeMsg>
<students>
<student>
<name>李四</name>
<sex>男</sex>
</student>
<student>
<name>王五</name>
<sex>女</sex>
</student>
</students>
</classAndGrade> 

上例可以看出只显示了name和sex结点,而没有显示age结点。
2.XmlAccessType.FIELD
这个属性是将类中非静态的属性都映射到xml中,并且不需要加get/set方法

@XmlAccessorType(value = XmlAccessType.FIELD)
public class Student { private String name;
private Integer age;
private static String sex; /**
* @Title:Student
* @param:@param name
* @param:@param age
* @param:@param sex
* @throws
*/
public Student(String name, Integer age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}

我在将sex属性写为静态,执行结果如下:

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<classAndGrade>
<classAndGradeMsg>
<classTeacher>张三</classTeacher>
<name>三年二班</name>
<personNum></personNum>
</classAndGradeMsg>
<students>
<student>
<age></age>
<name>李四</name>
</student>
<student>
<age></age>
<name>王五</name>
</student>
</students>
</classAndGrade> 

sex 确实没有被映射。
3.XmlAccessType.PUBLIC_MEMBER
这个属性值,是@XmlAccessorType的默认默认值,它会将属性为public的属性或者get/set方法同时为public的属性映射成xml。

@XmlAccessorType(value = XmlAccessType.PUBLIC_MEMBER)
public class Student { public String name;
private Integer age;
public String sex; /**
* @Title:Student
* @param:@param name
* @param:@param age
* @param:@param sex
* @throws
*/
public Student(String name, Integer age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
} private String getName() {
return name;
} private void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
}

上例中 name 的属性为public的 get/set方法为private的,age的属性为private的且只有一个get方法,sex只有一个public的方法执行结果如下:

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<classAndGrade>
<classAndGradeMsg>
<classTeacher>张三</classTeacher>
<name>三年二班</name>
<personNum></personNum>
</classAndGradeMsg>
<students>
<student>
<name>李四</name>
<sex>男</sex>
</student>
<student>
<name>王五</name>
<sex>女</sex>
</student>
</students>
</classAndGrade> 

4.XmlAccessType.NONE
这个属性表示任何属性都不会被映射到xml中,除非使用其他注解,如@XmlElement

@XmlAccessorType(value = XmlAccessType.NONE)
public class Student { @XmlElement(name="name")
public String name;
private Integer age;
public String sex; /**
* @Title:Student
* @param:@param name
* @param:@param age
* @param:@param sex
* @throws
*/
public Student(String name, Integer age, String sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}

执行结果如下:

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<classAndGrade>
<classAndGradeMsg>
<classTeacher>张三</classTeacher>
<name>三年二班</name>
<personNum></personNum>
</classAndGradeMsg>
<students>
<student>
<name>李四</name>
</student>
<student>
<name>王五</name>
</student>
</students>
</classAndGrade> 

只映射了name

  • @XmlAccessorOrder
    类级别的注解。控制生成属性映射xml结点的顺序。其中有一个value属性,可以设置排序方式,XmlAccessOrder.ALPHABETICAL 为按照字母顺序进行排序, XmlAccessOrder.UNDEFINED按照属性顺序进行排序,默认为XmlAccessOrder.UNDEFINED
@XmlAccessorOrder(value = XmlAccessOrder.ALPHABETICAL)
public class Student {

现在执行结果如下:

<?xml version="1.0" encoding="GBK" standalone="yes"?>
<classAndGrade>
<classAndGradeMsg>
<classTeacher>张三</classTeacher>
<name>三年二班</name>
<personNum></personNum>
</classAndGradeMsg>
<students>
<student>
<age></age>
<name>李四</name>
<sex>男</sex>
</student>
<student>
<age></age>
<name>王五</name>
<sex>女</sex>
</student>
</students>
</classAndGrade>
 
  • @XmlJavaTypeAdapter
    这个注解主要是解决一些数据格式化问题的,比如时间格式化。
    我在我的Student类中加入time字段。
public Date time; 

但是直接执行的话这个xml映射的结果为:

<time>--04T17::38.158+:</time> 

但是,这不是我想要的结果,我需要格式化之后的数据。
创建时间格式化类Dateformatting

public class Dateformatting extends XmlAdapter<String, Date> {

    private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
@Override
public Date unmarshal(String date) throws Exception {
return SDF.parse(date);
} @Override
public String marshal(Date date) throws Exception {
return SDF.format(date);
} } 

在时间属性上加上@XmlJavaTypeAdapter(Dateformatting.class)

@XmlJavaTypeAdapter(Dateformatting.class)
public Date time; 

执行结果:

<time>-- ::</time> 

此时时间已经被格式化成我们想要的格式。

  • @XmlElementWrapper
    这个注解是加载集合上面的,我在上面学生List上就是加了这个注解。
    
@XmlElementWrapper(name="students")
@XmlElement(name="student")
public List<Student> getStudents() {
return students;
  • @XmlAttribute
    这个注解会将属性变为上一个结点的属性
  
 @XmlAttribute(name="name")
public String name; 

执行结果为

        
<student name="李四">
<sex>男</sex>
<time>-- ::</time>
</student> 
  • @XmlType
    类级别的注解,这个注解可以自定义排序,使用propOrder 属性。
@XmlType(propOrder = {"time", "sex", "age", "name"})
public class Student {

执行结果为:        

<student>
<time>-- ::</time>
<sex>女</sex>
<age></age>
<name>王五</name>
</student>

上面就是我们在使用JAXB时常用的一些注解,以及用法。

最后附上我自己使用的xmlUtil的工具类。

/**
* xml util
* @author wuyouxin
*
*/
public class XmlUtil { /**
* JAVA bean 转 xml
* @param obj
* @param zlass
* @return
* @throws JAXBException
*/
public static String beanToXml (Object obj, Class<?> zlass) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(zlass);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "GBK");
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
StringWriter writer = new StringWriter();
marshaller.marshal(obj,writer);
return writer.toString();
} /**
* xml 转 JAVA bean
* @param xml
* @param zlass
* @return
* @throws JAXBException
*/
public static Object xmlToBean (String xml, Class<?> zlass) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(zlass);
Unmarshaller unmarshaller = context.createUnmarshaller();
Object object = unmarshaller.unmarshal(new StringReader(xml));
return object;
} }

-------------------- END ---------------------


最后附上作者的微信公众号地址和博客地址


公众号:wuyouxin_gzh




Herrt灬凌夜:https://www.cnblogs.com/wuyx/

 

使用JAXB实现Bean与Xml相互转换的更多相关文章

  1. 启动服务报错:nested exception is java.lang.NoSuchMethodError: org.apache.cxf.common.jaxb.JAXBUtils.closeUnmarshaller(Ljavax/xml/bind/Unmarshaller;)V

    1.启动tomcat时报错:Error creating bean with name 'payInfService': Invocation of init method failed; neste ...

  2. JAXB—Java类与XML文件之间转换

    JAXB-Java类与XML文件之间转换 简介         JAXB(Java Architecture for XML Binding) 是一个业界的标准,是一项可以根据XML Schema产生 ...

  3. JAVA bean与XML互转的利器---XStream

    最近在项目中遇到了JAVA bean 和XML互转的需求, 本来准备循规蹈矩使用dom4j忽然想起来之前曾接触过的XStream, 一番研究豁然开朗,利器啊利器, 下来就XStream的一些用法与大家 ...

  4. java对象与xml相互转换 ---- xstream

    XStream是一个Java对象和XML相互转换的工具,很好很强大.提供了所有的基础类型.数组.集合等类型直接转换的支持. XStream中的核心类就是XStream类,一般来说,熟悉这个类基本就够用 ...

  5. Excel与XML相互转换 - C# 简单实现方案

    Excel与XML相互转换 - C# 简单实现方案 在日常工作中,我需要将数据存储在Excel中进行数据分析和处理,然后再将数据转换为XML格式进行跨平台的数据交换.网上搜索Excel转换为XML的实 ...

  6. JAVA Bean和XML之间的相互转换 - XStream简单入门

    JAVA Bean和XML之间的相互转换 - XStream简单入门 背景介绍 XStream的简介 注解简介 应用实例 背景介绍 我们在工作中经常 遇到文件解析为数据或者数据转化为xml文件的情况, ...

  7. lientDataset的Delta与XML相互转换

    一个ClientDataset的Delta与XML相互转换的文章:大家都知道TClientDataSet的Delta属性保存数据集的变化,但是Delta是OleVariant类型的属性,这样如果用De ...

  8. Spring基础使用(一)--------IOC、Bean的XML方式装配

    基础 1.xml文件基础格式: <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns=&q ...

  9. JSON对象与XML相互转换工具类

    依赖jar <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId ...

随机推荐

  1. Java基础-SSM之mybatis一对多和多对一关系映射

    Java基础-SSM之mybatis一对多和多对一关系映射 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.准备测试环境(创建数据库表)  1>.创建customers表: ...

  2. Kafka 0.8 Consumer设计解析

    摘要 本文主要介绍了Kafka High Level Consumer,Consumer Group,Consumer Rebalance,Low Level Consumer实现的语义,以及适用场景 ...

  3. bzoj千题计划277:bzoj4513: [Sdoi2016]储能表

    http://www.lydsy.com/JudgeOnline/problem.php?id=4513 f[i][0/1][0/1][0/1] 从高到低第i位,是否卡n的上限,是否卡m的上限,是否卡 ...

  4. UVA 12307 Smallest Enclosing Rectangle

    https://vjudge.net/problem/UVA-12307 求覆盖所有点的最小矩形面积.周长 相当于求凸包的最小面积外接矩形.最小周长外接矩形 结论: 这个矩形一定有一条边和凸包上一条边 ...

  5. 获取web页面xpath

    1. Open Chrome 2. Right click the element that you want to get xpath 3. select "Inspector" ...

  6. HTML5 移动开发(CSS3设计移动页面样式)

    1.如何创建CSS样式表 2.CSS3的卓越特性 3.基于设备属性改变样式的媒体查询 4.如何使用属性改变元标签创建更美观移动页面   层叠样式表是移动WEB开发中的一个重要组成部分,本次分享将学到如 ...

  7. iOS8 自定义navigationbar 以及 UIBarButtonItem 边距问题

    一.自定义navigationbar - (void)initNavigationBar{ [self.navigationController setNavigationBarHidden:YES] ...

  8. HDU 1262 寻找素数对 模拟题

    题目描述:输入一个偶数,判断这个偶数可以由哪两个差值最小的素数相加,输出这两个素数. 题目分析:模拟题,注意的是为了提高效率,在逐个进行判断时,只要从2判断到n/2就可以了,并且最好用打表法判断素数. ...

  9. Zookeeper笔记之quota

    一.节点配额概述 zookeeper中可以往节点存放数据,但是一般来说存放数据总是要有个度量的对吧,不然空间就那么大,如果某个节点将空间全占用了其它节点没得用了,所以zookeeper提供了一个对节点 ...

  10. 上传插件dropzone.js实例

    dropzone.js默认是Ajax上传图片给服务器,那么如何获取到图片名呢?其实我们是可以通过dropzone的success函数获取到服务器返回的数据 dropzone.js在HTML的配置如下: ...