由于XML在分布式系统中应用如此广泛,而java又是开发网络和分布式系统可选的最佳运行环境之一,因此,java提供了很多的库,使编程人员能够轻松处理XML数据。在早期,java主要以JAXP定义的相关接口和类处理XML文档。JAXP中包括基于树结构的DOM和基于流方式的SAX和StAX。随着面向对象技术的不断发展,像JAXP这样低层次的XML处理方式,无法满足日益增长的程序规模的需求,因此XOM(XML文档和对象映射)被提出,Java通过对XOM的需求的研究(JSR222),提出了JAXB框架。JAXB框架主要是解决java对象与XML文档映射问题。
Spring技术已经发展到3.0版本,在过去的几年里,Spring真的如其名字一样给计算机网络服务编程带来了春天。现在Spring技术已经得到了国内软件行业的认可,并且有继续扩展的趋势。Spring回避了EJB的缺陷,发扬了EJB的优点,已然成为JavaEE的一个经典框架。
最近在研究Restful服务技术,而XML是Restful的一个主要信息载体,使用JAXB完成XML与Java对象的映射又是比较常用的策略(实际使用Castor等框架也可完成XOM)。在Restful中,我们先定义一个通信两端的通信协议(一般是一个schema文件,描述了通信两端交换的数据格式和内容),之后两端各自根据通信协议完成各自的实现,因此,通信两端可以是编程环境和运行环境异构的。例如:通信两端中,一端是java程序,另一端是c程序,而他们之间的通信使用Restful(Http协议)并且信息载体是XML,java和c都可以处理XML文档,获取文档中需要的信息(XML信息的内容和格式由schema定义的),因此就完成了跨平台,跨执行环境的通信。在java端,JAXB可以通过Schema自动生成Java类对象,并且JAXB按照Schema的标准将java对象编组到XML文档中,也能从XML文档中解组出java对象,这样就大大提高了对通信信息的处理能力。
对于java来说,使用Restful服务的简单方法就是使用Spring的MVC,因为Spring的MVC本身就是基于Restful的目的编写的(实际上,JavaEE6提供的JAX-RS是java对Restful的实现框架,但是,我们希望应用更多的Spring特性(依赖注入和控制反转)来简化我们的服务搭建,因此使用的是SpringMVC来完成Restful服务)。
综上,我们看到了在Spring中使用JAXB的重要性,以及它在我们的Restful服务搭建环节上的地位,下面将简述如何在Spring中使用JAXB2.
1、编写schema文档
我们打算创建两个数据模型,一个是student.xsd,描述了关于student的定义,一个是teacher.xsd描述teacher的定义。定义两个xsd文件的目的是为了解释一个JAXBContent能包含多个根元素,并没有特殊意义。
Student.xsd
xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="student">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
xsd:sequence>
<xsd:attribute name="id" type="xsd:int"/>
xsd:complexType>
xsd:element>
xsd:schema>
Teacher.xsd
xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="teacher">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
xs:sequence>
xs:complexType>
xs:element>
xs:schema>
2. 使用xjc编译生成java类
JAXB能够从schema转换出java的类,同时也能从java类转换出schema。根据我们前面的分析,schema实际是通信双方的标准,因此,先定义出schema,之后通过schema生成java类似乎更合理。因此我们采用xjc从schema生成java类。
使用命令行,转换出student类,输入如下信息:
I:\programs\eclipse\SpringJAXBTest\src>xjc -p cn.edu.upc.upcgrid.guan.springjaxb
.student Student.xsd
xjc (XML to Java Compiler)是java提供的工具,在java安装后就可以使用这个工具(注意要将java的环境变量配置正确),-p 后面的参数是生成类的包名和转换的schema文件的路径。
同理使用命令行,将Teacher的schema转换成teacher类。
I:\programs\eclipse\SpringJAXBTest\src>xjc -p com.upc.upcgrid.guan.springjaxb.st
udent Teacher.xsd
现在,刷新我们的工程,会出现有xjc生成的类。(注意,ObjectFactory没有用处,因此可以直接删除,ObjectFactory在某些情况下有用,不过那是复杂的schema映射,比如choice元素等,如果希望了解更多,请参考我的其他关于JAXB的博客)。
Student.java类的内容大致如下:
package com.upc.upcgrid.guan.springjaxb.student;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="student")
public class Student {
@XmlElement(required = true)
protected String name;
@XmlAttribute
protected Integer id;
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
public Integer getId() {
return id;
}
public void setId(Integer value) {
this.id = value;
}
}
生成的Teacher.java类的大致内容如下:
package com.upc.upcgrid.guan.springjaxb.student;
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 javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"name"
})
@XmlRootElement(name = "teacher")
public class Teacher {
@XmlElement(required = true)
protected String name;
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
}
可以看出,xjc生成的Teacher和Student类只不过是一些get和set方法,并且添加了一些标记(在JAXB中,如果会使用这些标记,可以在自定义的类中使用这些标记,就不用定义schema)。
3. 配置Spring环境
这里为了简单起见,我们不使用XML方式配置Spring,而是采用Annotation的方式对Spring进行配置。
这里有两个类,SpringConfigure用来替代以前的spring-servlet.xml(就是spring的配置文档)。为了方便使用,我们又创建一个spring的注入类MarshalAndUnmarshalService,此类包含两个成员变量,分别为Marshaller和Unmarshaller,我们可以使用这两个变量完成对Java对象的编组和对XML文档的解组。根据Spring的注入规则,我们看到Spring的配置文档中有一个Jaxb2Marshaller类bean实例,这个实例有一个特点,它既是Marshaller类型,也是Unmarshaller类型,因此,在Spring依赖注入的过程中,MarshalAndUnmarshalService类中的marshaller和unmarshaller实际注入的是同一个实例(即:Jaxb2Marshaller类的实例)。
Spring的配置文件SpringConfigure.java
package com.upc.upcgrid.guan.springjaxb;
import java.util.HashMap;
import java.util.Map;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import com.upc.upcgrid.guan.springjaxb.student.Student;
import com.upc.upcgrid.guan.springjaxb.student.Teacher;
@Configuration
public class SpringConfigure {
public @Bean Jaxb2Marshaller jaxb2Marshaller()//配置JAXB2Context
{
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();//创建JAXB上下文环境
Map
properties.put(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); //放置xml自动缩进属性
marshaller.setClassesToBeBound(Student.class,Teacher.class);//映射的xml类放入JAXB环境中
marshaller.setMarshallerProperties(properties);//设置Marshaller属性
return marshaller;
}
public @Bean MarshalAndUnmarshalService marshalAndUnmarshalService()
{
return new MarshalAndUnmarshalService();//创建和使用JAXB
}
}
MarshalAndUnmarshalService.java
package com.upc.upcgrid.guan.springjaxb;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.stereotype.Component;
@Component
public class MarshalAndUnmarshalService{
private Marshaller marshaller;//注入Marshaller
private Unmarshaller unmarshaller;//注入Unmarshaller
@Autowired
public void setMarshaller(Marshaller marshaller) {
this.marshaller = marshaller;
}
public Marshaller getMarshaller() {
return marshaller;
}
@Autowired
public void setUnmarshaller(Unmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
}
public Unmarshaller getUnmarshaller() {
return unmarshaller;
}
}
4. 编写测试程序。
现在我们的准备工作已经结束,剩下的就是测试,在MainTest.java中给出了如何使用Spring进行XOM映射。
在main函数中,先创建需要编组的对象,之后构建Spring环境,从Spring环境中获取到marshaller和unmarshaller,最后完成编组和解组。
package com.upc.upcgrid.guan.springjaxb;
import java.io.File;
import java.io.IOException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.oxm.XmlMappingException;
import com.upc.upcgrid.guan.springjaxb.student.Student;
import com.upc.upcgrid.guan.springjaxb.student.Teacher;
public class MainTest {
public static void main(String[] args) throws XmlMappingException, IOException {
//创建两个文件,分别输出不同的对象
File file = new File("student.xml");
File tFile = new File("teacher.xml");
//创建学生
Student student = new Student();
student.setId(21231);
student.setName("mary");
//创建teacher
Teacher teacher = new Teacher();
teacher.setName("Lucy");
//创建spring上下文(此时spring开始分析并创建单例类的对象)
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfigure.class);
//获取到jaxb使用的工具
MarshalAndUnmarshalService maus = ac.getBean(MarshalAndUnmarshalService.class);
//将学生和教师数据编组到文件
maus.getMarshaller().marshal(student, new StreamResult(file));
maus.getMarshaller().marshal(teacher, new StreamResult(tFile));
//将学生和教师信息解组到对象
Student s = (Student) maus.getUnmarshaller().unmarshal(new StreamSource(file));
Teacher t = (Teacher) maus.getUnmarshaller().unmarshal(newStreamSource(tFile));
//输出学生和教师中的内容
System.out.println(s.getName());
System.out.println(t.getName());
}
}
标准输出:
2011-6-23 20:22:54 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@1113708: startup date [Thu Jun 23 20:22:54 CST 2011]; root of context hierarchy
2011-6-23 20:22:54 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1f33675: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,springConfigure,jaxb2Marshaller,marshalAndUnmarshalService]; root of factory hierarchy
2011-6-23 20:22:54 org.springframework.oxm.jaxb.Jaxb2Marshaller createJaxbContextFromClasses
信息: Creating JAXBContext with classes to be bound [class com.upc.upcgrid.guan.springjaxb.student.Student,class com.upc.upcgrid.guan.springjaxb.student.Teacher]
mary
Lucy
生成的XML文档:
Student.xml
xml version="1.0" encoding="UTF-8" standalone="yes"?>
<student id="21231">
<name>maryname>
student>
Teacher.xml
xml version="1.0" encoding="UTF-8" standalone="yes"?>
<teacher>
<name>Lucyname>
teacher>
程序结构:
参考:
Spring官方文档
JAXB官方文档:http://jaxb.java.net/tutorial/index.html