Spring和JAXB2.0結合使用

由於XML在分佈式系統中應用如此廣泛,而java又是開發網絡和分佈式系統可選的最佳運行環境之一,因此,java提供了很多的庫,使編程人員能夠輕鬆處理XML數據。在早期,java主要以JAXP定義的相關接口和類處理XML文檔。JAXP中包括基於樹結構的DOM和基於流方式的SAXStAX。隨着面向對象技術的不斷髮展,像JAXP這樣低層次的XML處理方式,無法滿足日益增長的程序規模的需求,因此XOMXML文檔和對象映射)被提出,Java通過對XOM的需求的研究(JSR222),提出了JAXB框架。JAXB框架主要是解決java對象與XML文檔映射問題。

       Spring技術已經發展到3.0版本,在過去的幾年裏,Spring真的如其名字一樣給計算機網絡服務編程帶來了春天。現在Spring技術已經得到了國內軟件行業的認可,並且有繼續擴展的趨勢。Spring迴避了EJB的缺陷,發揚了EJB的優點,已然成爲JavaEE的一個經典框架。

       最近在研究Restful服務技術,而XMLRestful的一個主要信息載體,使用JAXB完成XMLJava對象的映射又是比較常用的策略(實際使用Castor等框架也可完成XOM)。在Restful中,我們先定義一個通信兩端的通信協議(一般是一個schema文件,描述了通信兩端交換的數據格式和內容),之後兩端各自根據通信協議完成各自的實現,因此,通信兩端可以是編程環境和運行環境異構的。例如:通信兩端中,一端是java程序,另一端是c程序,而他們之間的通信使用RestfulHttp協議)並且信息載體是XMLjavac都可以處理XML文檔,獲取文檔中需要的信息(XML信息的內容和格式由schema定義的),因此就完成了跨平臺,跨執行環境的通信。在java端,JAXB可以通過Schema自動生成Java類對象,並且JAXB按照Schema的標準將java對象編組到XML文檔中,也能從XML文檔中解組出java對象,這樣就大大提高了對通信信息的處理能力。

       對於java來說,使用Restful服務的簡單方法就是使用SpringMVC,因爲SpringMVC本身就是基於Restful的目的編寫的(實際上,JavaEE6提供的JAX-RSjavaRestful的實現框架,但是,我們希望應用更多的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類似乎更合理。因此我們採用xjcschema生成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文件的路徑。

       同理使用命令行,將Teacherschema轉換成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生成的TeacherStudent類只不過是一些getset方法,並且添加了一些標記(在JAXB中,如果會使用這些標記,可以在自定義的類中使用這些標記,就不用定義schema)。

3. 配置Spring環境

這裏爲了簡單起見,我們不使用XML方式配置Spring,而是採用Annotation的方式對Spring進行配置。

這裏有兩個類,SpringConfigure用來替代以前的spring-servlet.xml(就是spring的配置文檔)。爲了方便使用,我們又創建一個spring的注入類MarshalAndUnmarshalService,此類包含兩個成員變量,分別爲MarshallerUnmarshaller,我們可以使用這兩個變量完成對Java對象的編組和對XML文檔的解組。根據Spring的注入規則,我們看到Spring的配置文檔中有一個Jaxb2Marshallerbean實例,這個實例有一個特點,它既是Marshaller類型,也是Unmarshaller類型,因此,在Spring依賴注入的過程中,MarshalAndUnmarshalService類中的marshallerunmarshaller實際注入的是同一個實例(即: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<String,Object> properties = new HashMap<String, Object>();//創建映射,用於設置Marshaller屬性

       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環境中獲取到marshallerunmarshaller,最後完成編組和解組。

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>mary</name>

</student>

Teacher.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<teacher>

    <name>Lucy</name>

</teacher>

 

程序結構:

Spring和JAXB2.0結合使用

參考:

Spring官方文檔

JAXB官方文檔:http://jaxb.java.net/tutorial/index.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章