zoukankan      html  css  js  c++  java
  • 使用JAXB实现Bean与Xml相互转换

    最近几天,我自己负责的应用这边引入了一个新的合作方,主要是我这边调用他们的接口,但是有个很坑的地方,他们传参居然不支持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(2, "三年二班", "张三");
            classAndGrade.setClassAndGrade(classAndGradeMsg);
            List<Student> list = new ArrayList<Student>();
            Student s1 = new Student("李四", 12, "");
            Student s2 = new Student("王五", 12, "");
            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>2</personNum>
        </classAndGrade>
        <students>
            <student>
                <age>12</age>
                <name>李四</name>
                <sex>男</sex>
            </student>
            <student>
                <age>12</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>2</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>2</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>2</personNum>
        </classAndGradeMsg>
        <students>
            <student>
                <age>12</age>
                <name>李四</name>
            </student>
            <student>
                <age>12</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>2</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>2</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>2</personNum>
        </classAndGradeMsg>
        <students>
            <student>
                <age>12</age>
                <name>李四</name>
                <sex>男</sex>
            </student>
            <student>
                <age>12</age>
                <name>王五</name>
                <sex>女</sex>
            </student>
        </students>
    </classAndGrade>
     
    • @XmlJavaTypeAdapter
      这个注解主要是解决一些数据格式化问题的,比如时间格式化。
      我在我的Student类中加入time字段。
    public Date time; 

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

    <time>2019-01-04T17:52:38.158+08:00</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>2019-01-04 05:59:42</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>2019-01-04 06:06:38</time>
    </student> 
    • @XmlType
      类级别的注解,这个注解可以自定义排序,使用propOrder 属性。
    @XmlType(propOrder = {"time", "sex", "age", "name"})
    public class Student {

    执行结果为:        

    <student>
        <time>2019-01-04 06:13:58</time>
        <sex>女</sex>
        <age>12</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/

     
  • 相关阅读:
    开发DBA(APPLICATION DBA)的重要性
    SQL有外连接的时候注意过滤条件位置
    程序与bug
    Dalvik虚拟机进程和线程的创建过程分析
    Dalvik虚拟机简要介绍和学习计划
    Dalvik虚拟机的运行过程分析
    JRE和JDK的概念
    myeclipse6.0.1(内置了eclipse)安装及其配置
    JDK 环境变量如何设置
    jdk1.5和tomcat5.5免安装的环境配置
  • 原文地址:https://www.cnblogs.com/wuyx/p/10221813.html
Copyright © 2011-2022 走看看