JAXB学习

一、简介

JAXB(Java Architecture for XML Binding) 是一个业界的标准,是一项可以根据XML Schema产生Java类的技术。
该过程中,JAXB也提供了将XML实例文档反向生成Java对象树的方法,并能将Java对象树的内容重新写到XML实例文档。
从另一方面来讲,JAXB提供了快速而简便的方法将XML模式绑定到Java表示,从而使得Java开发者在Java应用程序中能方便地结合XML数据和处理函数。

样例:

  • Person.class
@XmlRootElement
public class Person {
    //主键
    private int id;
    //姓名
    private String name;
    //性别
    private String sex;
    //地址
    private String address;

    public int getId() {
        return id;
    }

    @XmlElement
    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    @XmlElement
    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    @XmlElement
    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    @XmlElement
    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    public Person(int id, String name, String sex, String address) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.address = address;
    }
}
  • Utils
public class JAXBUtils {

    /**
     * xml 文件转 java对象
     */
    public static void generateBean() {
        File file = new File("E:\\person.xml");
        JAXBContext jc = null;
        try {
            //根据Person类生成上下文对象
            jc = JAXBContext.newInstance(Person.class);
            //从上下文中获取Unmarshaller对象,用作将xml解组(转换)为java 对象
            Unmarshaller uma = jc.createUnmarshaller();
            //解组
            Person person = (Person) uma.unmarshal(file);
            System.out.println(person);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }

    /**
     * 对象转 xml 生成xml文件
     */
    public static void generateXML() {
        Person person = new Person(1, "张三", "男", "朝阳区");

        File file = new File("E:\\person.xml");
        JAXBContext jc = null;
        try {
            //根据Person类生成上下文对象
            jc = JAXBContext.newInstance(Person.class);
            //从上下文中获取Marshaller对象,用作将bean编组(转换)为xml
            Marshaller ma = jc.createMarshaller();
            //以下是为生成xml做的一些配置
            //格式化输出,即按标签自动换行,否则就是一行输出
            ma.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            //设置编码(默认编码就是utf-8)
            ma.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
            //是否省略xml头信息,默认不省略(false)
            ma.setProperty(Marshaller.JAXB_FRAGMENT, false);

            //编组
            ma.marshal(person, file);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }

    /**
     *  对象转 xml 字符串
     */
    public static String beanToXml(Class clazz, Object object) throws JAXBException {
        // 获取上下文对象
        JAXBContext context = JAXBContext.newInstance(clazz);
        // 根据上下文获取marshaller对象
        Marshaller marshaller = context.createMarshaller();
        // 设置编码字符集
        marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
        // 格式化XML输出,有分行和缩进
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        // 去掉生成xml的默认报文头
        marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        marshaller.marshal(object, baos);
        return new String(baos.toByteArray());
    }

    /**
     * xml 字符串 转 java对象
     */
    public static <T> T  xmlToBean(Class<T> clazz,String xml) throws JAXBException{
        File file = new File("E:\\person.xml");
        //根据class生成上下文对象
        JAXBContext jc = JAXBContext.newInstance(clazz);
        //从上下文中获取Unmarshaller对象,用作将xml解组(转换)为java 对象
        Unmarshaller uma = jc.createUnmarshaller();
        //解组
        Object obj =  uma.unmarshal(new ByteArrayInputStream(xml.getBytes()));
        return clazz.cast(obj);
    }
}

二、 结果测试

  • generateXML()
    在这里插入图片描述
    此xml相当于该xsd文件:
<xs:element name="person">
	<xs:complexType>
		<xs:sequence>
			<xs:element type="xs:string" name="address" minOccurs="0"/>
			<xs:element type="xs:int" name="id" minOccurs="0"/>
			<xs:element type="xs:string" name="name" minOccurs="0"/>
			<xs:element type="xs:string" name="sex" minOccurs="0"/>
		</xs:sequence>
	</xs:complexType>
</xs:element>
  • generateBean()

在这里插入图片描述

  • beanToXml(Class clazz,Object object)

在这里插入图片描述

  • xmlToBean(Class clazz,String xml)

在这里插入图片描述

从jdk1.7开始,JAXB就对解组和编组的方法进行了更简单的封装,所以实际项目中除非自己要进行个性化设置,否则大可不用自己再创建JAXBContext实例,直接通过JAXB静态调用相应的工具方法就行了,于是上面的测试方法可以写的更简练些:

例:

   public void generateXML() {
        Person person = new Person("abc", "男", "北京", "朝阳区");
        File file = new File("E:\\person.xml");
        JAXB.marshal(person, file);
    }
 
    public void generateBean() {
        File file = new File("E:\\person.xml");
        Person person = JAXB.unmarshal(file, Person.class);
 
        System.out.println(person);
    }

直接使用默认的配置,已经足够应付大多数情况。

三、常用注解

  • @XmlRootElement

作用

类级别的注解,将类映射为xml全局元素,也就是根元素。就像spring配置文件中的beans。上面的例子中我将该注解用在了person类上,生成了根元素。常与@XmlType,@XmlAccessorType,@XmlAccessorOrder连用。

属性

该注解含有name和namespace两个属性。namespace属性用于指定生成的元素所属的命名空间。name属性用于指定生成元素的名字,若不指定则默认使用类名小写作为元素名。

修改上面的例子,在该注解上使用name属性:

@XmlRootElement(name = "personBase")
public class Person {
    private int id;
    private String name;
    ...
    ...
    //省略下面代码
}    

在这里插入图片描述

  • @XmlElement

作用

字段,方法,参数级别的注解。该注解可以将被注解的字段(非静态),或者被注解的get/set方法对应的字段映射为本地元素,也就是子元素。默认使用字段名或get/set方法去掉前缀剩下部分小写作为元素名(在字段名和get/set方法符合命名规范的情况下)。
上面例子中,id、addr、name、gender、area都被映射成了元素的子元素。下文会配合@XmlAccessorType注解详细讲解该注解的用法。常与@XmlValue,@XmlJavaTypeAdapter,@XmlElementWrapper连用。

属性

该注解的属性常用的属性有有:name、nillable、required、namespace、defaultValue
name属性可以指定生成元素的名字,同@XmlRootElement注解的name属性一样,不再举例。
nillable属性可以指定元素的文本值是否可以为空,默认为false。修改上面例子:

@XmlElement(nillable = true)
    public void setName(String name) {
    this.name = name;

则生成的xsd(为了节省篇幅,只截取必要的片段)为:

<xs:element name="name" type="xs:string" nillable="true" minOccurs="0"/>

required属性可以指定该元素是否必须出现,默认为false,所以在xsd中会有对应的属性minOccurs=“0”。修改该属性为true

@XmlElement(nillable = true, required = true)
    public void setName(String name) {
    this.name = name;
}

生成的xsd文件为:

<xs:element name="name" type="xs:string" nillable="true" minOccurs="1"/>

namespace属性可以指定该元素所属的命名空间
defaultValue属性可以指定该元素默认的文本值

  • @XmlAttribute

作用

字段和方法级别的注解。
该注解会将字段或get/set方法对应的字段映射成本类对应元素的属性,属性名默认使用字段名或get/set方法去掉前缀剩下部分首字母小写(在字段名和get/set方法符合命名规范的情况下)。

修改上面例子:

@XmlAttribute
public void setSex(String sex) {
	this.sex = sex;
}

生成的xml:

在这里插入图片描述

<xs:element name="personBase">
	<xs:complexType>
		<xs:sequence>
			<xs:element type="xs:string" name="address" minOccurs="0"/>
			<xs:element type="xs:int" name="id" minOccurs="0"/>
			<xs:element type="xs:string" name="name" minOccurs="0"/>
		</xs:sequence>
		<xs:attribute type="xs:string" name="sex"/>
	</xs:complexType>
</xs:element>

属性

该注解有name,required,namespace三个属性。用法和@XmlElement注解相同,不再举例

  • @XmlTransient

作用

类,字段,方法级别的注解。可使JAXB在映射xml元素时忽略被注解的类,字段,get/set对应字段。需要注意的是该注解与所有其他JAXB注释相互排斥,也就是说与其他注释连用就会报错

修改上面例子:

@XmlTransient
public void setId(int id) {
    this.id = id;
}

生成的xml:
在这里插入图片描述

属性

该注解没有属性。

  • @XmlAccessorType

作用

包和类级别的注解。javaEE的API对该注解的解释是:控制字段是否被默认序列化。
通俗来讲,就是决定哪些字段或哪些get/set方法对应的字段会被映射为xml元素,需要注意的是字段或get/set方法的访问权限(public/private)会影响字段是否被映射为xml元素,下面会详细讲解。

属性

该注解只有一个value属性,可取的值是一个名为XmlAccessType的枚举类型里的值。

下面详细看一下这几个值分别有什么用:

XmlAccessType.PROPERTY

  1. 当使用了该值,只要字段有对应的get/set方法对(注意是成对出现,只有其中一个不会发生映射),不需要使用@XmlElement注解,不论该方法的访问权限是什么(即使是private),jaxb就会将该字段映射成xml元素。不过最好加上@XmlElement注解,get/set方法任选一个即可,都加上会报错。
  2. 若在一个字段有set/get方法对但又在字段上添加@XmlElement注解会报属性重复的错误。
  3. 若没有set/get方法对,则需要在字段上使用@XmlElement注解才可以映射为xml元素,否则不会发生映射。
  4. 若get/set方法上使用了@XmlTransient注解,但想要对应字段发生映射,需要在对应字段上添加@XmlElement注解,此时不会报错,并将该字段映射为xml元素。

XmlAccessType.FIELD

  1. 每个访问权限为public的字段,或者每个访问权限为public的get/set方法对,都会将字段映射为xml元素,即使不使用@XmlElement,但最好加上。不可同时存在public字段和对应的get/set方法对,不然会报属性重复的错误。
  2. 若使用@XmlElement注解,需要注意只能在字段或get/set方法添加,两者任选其一,否则会报属性重复的错误。
  3. 若字段不为public,get/set方法为public并使用了@XmlTransient,需要在字段上添加@XmlElement才会发生映射。
  4. 若字段为public并使用了@XmlTransient,get/set方法对不为public,需要在get/set方法上使用@XmlElement才会映射。

XmlAccessType.NONE

  1. 任何字段,get/set方法对都不会发生映射,除非使用某些注解,如@XmlElement,@XmlElementWrapper等。
  • @XmlAccessorOrder

作用

包和类级别的注解。控制生成元素的顺序。

属性

只有一个value属性,可取的值是一个名为XmlAccessOrder的枚举类型的两个值:XmlAccessOrder.ALPHABETICALXmlAccessOrder.UNDEFINED
默认为XmlAccessOrder.UNDEFINED,代表按照类中字段的顺序生成元素的顺序。
另一个值则代表按照字母表的顺序对生成的元素排序。
但奇怪的是,只有jaxb按照field生成元素时,默认值才会生效,否则总是按照字母表的顺序排序。

  • @XmlElementWrapper

作用

字段和方法级别的注解。围绕被映射的xml元素生成包装元素。主要用在集合对象映射后生成包装映射结果的xml元素。

修改上面的例子,添加一个Key类,在Person类中添加一个Key类的Set集合,修改如下:

Key.class

@XmlRootElement
public class Key {
    private String roomNum;

    public Key() {
    }

    public Key(String roomNum) {
        this.roomNum = roomNum;
    }

    public String getRoomNum() {
        return roomNum;
    }

    @XmlElement
    public void setRoomNum(String roomNum) {
        this.roomNum = roomNum;
    }

    @Override
    public String toString() {
        return "Key{" +
                "roomNum='" + roomNum + '\'' +
                '}';
    }

}

Person.class

@XmlRootElement(name = "personBase")
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)

public class Person {
    //主键
    private int id;
    //姓名
    private String name;
    //性别
    private String sex;
    //地址
    private String address;

    private List<Key> key;

    public int getId() {
        return id;
    }


    @XmlElement
    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    @XmlElement
    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    @XmlElement
    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    @XmlElement
    public void setAddress(String address) {
        this.address = address;
    }

    public List<Key> getKey() {
        return key;
    }

    @XmlElement
    public void setKey(List<Key> key) {
        this.key = key;
    }

    public Person(int id, String name, String sex, String address, List<Key> key) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.address = address;
        this.key = key;
    }

    public Person() {
    }
}

生成的xml:
在这里插入图片描述

但同一元素应该需要被“包装”一下才显得有层次感,所以可以使用@XmlElementWrapper来实现:

@XmlElementWrapper(name = "keys")
@XmlElement
public void setKey(List<Key> key) {
    this.key = key;
}

生成的xml:
在这里插入图片描述

属性

该注解有name、nillable、namespace、required四个属性,用法同上,不再赘述。

  • @XmlJavaTypeAdapter

作用

包、类、字段,方法、参数级别的注解。解决java日期(Date),数字(Number)格式化问题

直接看例子,修改Person类,添加一个Date类型字段:

@XmlRootElement(name = "personBase")
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
public class Person {
    //...略
    private Date date = new Date();
 
    //...略
 
    public Date getDate() {
        return date;
    }
 
    @XmlElement
    public void setDate(Date date) {
        this.date = date;
    }
}

生成的xml
在这里插入图片描述
这样的date格式显然令人不满意,我们需要例如“2018-05-20”这样的格式。这就需要@XmlJavaTypeAdapter注解,自定义一个适配器来解决这个问题。该注解的用法就是自定义适配器并继承XmlAdapter类,实现里面的marshal和unmarshal方法,并在该注解上引用。修改例子:

自定义的DateAdapter:

public class DateAdapter extends XmlAdapter<String, Date> {
    private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");
 
    @Override
    public Date unmarshal(String date) throws Exception {
        return SDF.parse(date);
    }
 
    @Override
    public String marshal(Date date) throws Exception {
        return SDF.format(date);
    }
}

Person.class

@XmlJavaTypeAdapter(DateAdapter.class)
@XmlElement
public void setDate(Date date) {
    this.date = date;
}

生成的xml
在这里插入图片描述
属性

常用的就是value属性,其他属性请自行研究。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Spring Boot中整合JAXB,您可以按照以下步骤进行操作: 1. 添加依赖:在您的项目的pom.xml文件中,添加JAXB依赖项。 ```xml <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.1</version> </dependency> ``` 2. 创建Java类:创建要映射到XML的Java类。使用JAXB注解配置类和字段。 ```java @XmlRootElement public class Person { private String name; private int age; // 省略构造函数、getter和setter方法 } ``` 3. 创建XML转换工具类:创建一个工具类,用于执行XML转换操作。 ```java import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import java.io.File; public class JAXBUtils { public static void marshal(Object object, File file) throws JAXBException { JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass()); Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(object, file); } public static <T> T unmarshal(Class<T> clazz, File file) throws JAXBException { JAXBContext jaxbContext = JAXBContext.newInstance(clazz); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); return clazz.cast(unmarshaller.unmarshal(file)); } } ``` 4. 配置Spring Boot:在您的Spring Boot应用程序的配置类上添加JAXB相关的配置。 ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.xml.MarshallingHttpMessageConverter; import org.springframework.oxm.jaxb.Jaxb2Marshaller; @Configuration public class JAXBConfig { @Bean public Jaxb2Marshaller jaxb2Marshaller() { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setPackagesToScan("com.example.demo"); // 设置要扫描的包路径 return marshaller; } @Bean public HttpMessageConverter<Object> marshallingHttpMessageConverter(Jaxb2Marshaller jaxb2Marshaller) { return new MarshallingHttpMessageConverter(jaxb2Marshaller); } } ``` 5. 使用JAXB:在您的控制器或服务类中使用JAXB进行XML转换操作。 ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class PersonController { @Autowired private Jaxb2Marshaller jaxb2Marshaller; @GetMapping("/person") public Person getPerson() { Person person = new Person(); person.setName("John"); person.setAge(25); return person; } @GetMapping("/xml") public String getXml() { Person person = getPerson(); StringWriter writer = new StringWriter(); jaxb2Marshaller.marshal(person, new StreamResult(writer)); return writer.toString(); } } ``` 这样,当访问`/person`接口时,将返回一个Person对象的JSON表示。当访问`/xml`接口时,将返回Person对象的XML表示。 这就是在Spring Boot中整合JAXB的基本步骤。您可以根据需要进行扩展和自定义。希望对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值