本文在官方例子的基礎上,使用JAXB marshall 和 unmarshall 處理 xml資料
依照官方的例子,我們需要處理一個假期的請求,以下是Holiday的xml格式:
<Holiday xmlns="http://mycompany.com/hr/schemas">
<StartDate>2006-07-03</StartDate>
<EndDate>2006-07-07</EndDate>
</Holiday>
以下是Employee的xml格式:
<Employee xmlns="http://mycompany.com/hr/schemas">
<Number>42</Number>
<FirstName>Arjen</FirstName>
<LastName>Poutsma</LastName>
</Employee>
那麼一個請求就是下面的xml格式:
<HolidayRequest xmlns="http://mycompany.com/hr/schemas">
<Holiday>
<StartDate>2006-07-03</StartDate>
<EndDate>2006-07-07</EndDate>
</Holiday>
<Employee>
<Number>42</Number>
<FirstName>Arjen</FirstName>
<LastName>Poutsma</LastName>
</Employee>
</HolidayRequest>
我們需要為這個請求定義一個schema檔案hr.xsd:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:hr="http://mycompany.com/hr/schemas"
elementFormDefault="qualified"
targetNamespace="http://mycompany.com/hr/schemas">
<xs:element name="HolidayRequest">
<xs:complexType>
<xs:all>
<xs:element name="Holiday" type="hr:HolidayType"/>
<xs:element name="Employee" type="hr:EmployeeType"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:complexType name="HolidayType">
<xs:sequence>
<xs:element name="StartDate" type="xs:date"/>
<xs:element name="EndDate" type="xs:date"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="EmployeeType">
<xs:sequence>
<xs:element name="Number" type="xs:integer"/>
<xs:element name="FirstName" type="xs:string"/>
<xs:element name="LastName" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
在web.xml檔案中添加處理soap的servlet:
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<display-name>MyCompany HR Holiday Service</display-name>
<!-- take especial notice of the name of this servlet -->
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/spring-ws.xml</param-value>
</init-param>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/ws/*</url-pattern>
</servlet-mapping>
</web-app>
像SpringMVC有一個配置檔案一樣,spring-ws.xml是spring-ws的配置檔案。這裡解釋一下MessageDispatcherServlet,Spring-ws的服務端是圍繞着這個servlet設計的,這個servlet将收到的xml封包轉發到endpoint,這一點跟SpringMVC的DispacherServlet很相似。MessageDispatcherServlet處理請求的轉發過程如下圖所示。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiNwYDNwMjMwATOyETM1EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
spring-ws.xml的内容如下。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:sws="http://www.springframework.org/schema/web-services"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.chinamobile.cmss.eshub.ssb.wssimulator" />
<sws:annotation-driven />
<sws:dynamic-wsdl id="holiday" portTypeName="HumanResource" locationUri="/ws/holidayService/" targetNamespace="http://mycompany.com/hr/definitions">
<sws:xsd location="classpath:schema/hr.xsd" />
</sws:dynamic-wsdl>
</beans>
我們開啟自動掃描@Endpoint注解的類。接着定義暴露接口的wsdl路徑。
下面開始寫Endpoint。
package com.chinamobile.cmss.eshub.ssb.wssimulator.endpoint;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import com.chinamobile.cmss.eshub.ssb.wssimulator.entity.HolidayRequest;
@Endpoint
public class HolidayEndpoint {
private static final String NAMESPACE_URI = "http://mycompany.com/hr/schemas";
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "HolidayRequest")
public void handleHolidayRequest(@RequestPayload HolidayRequest holidayRequest)
throws Exception {
System.out.println(holidayRequest.toString());
}
}
這裡使用了eclipselink的JAXB,項目的pom.xml需要特殊加入的配置如下。
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.5.0</version>
</dependency>
編寫Holiday.java實體類如下,注意與xml
date
對應的java類型不是
Date
,而是
XMLGregorianCalendar
,xml與java資料類型的對應關系參考這裡。
package com.chinamobile.cmss.eshub.ssb.wssimulator.entity;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.datatype.XMLGregorianCalendar;
@XmlAccessorType(XmlAccessType.FIELD)
public class Holiday {
@XmlElement(namespace="http://mycompany.com/hr/schemas")
private XMLGregorianCalendar StartDate;
@XmlElement(namespace="http://mycompany.com/hr/schemas")
private XMLGregorianCalendar EndDate;
public XMLGregorianCalendar getStartDate() {
return StartDate;
}
public void setStartDate(XMLGregorianCalendar startDate) {
StartDate = startDate;
}
public XMLGregorianCalendar getEndDate() {
return EndDate;
}
public void setEndDate(XMLGregorianCalendar endDate) {
EndDate = endDate;
}
@Override
public String toString() {
return "Holiday [StartDate=" + StartDate + ", EndDate=" + EndDate + "]";
}
}
編寫Employee.java如下。
package com.chinamobile.cmss.eshub.ssb.wssimulator.entity;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee {
@XmlElement(namespace="http://mycompany.com/hr/schemas")
private int Number;
@XmlElement(namespace="http://mycompany.com/hr/schemas")
private String FirstName;
@XmlElement(namespace="http://mycompany.com/hr/schemas")
private String LastName;
public int getNumber() {
return Number;
}
public void setNumber(int number) {
Number = number;
}
public String getFirstName() {
return FirstName;
}
public void setFirstName(String firstName) {
FirstName = firstName;
}
public String getLastName() {
return LastName;
}
public void setLastName(String lastName) {
LastName = lastName;
}
@Override
public String toString() {
return "Employee [Number=" + Number + ", FirstName=" + FirstName + ", LastName=" + LastName + "]";
}
}
在Spring-ws中使用JAXB的時候要注意,每個類要注明namespace,否則會報
A descriptor with default root element
的錯誤。類中的每個屬性也要加
@XmlElement(namespace="")
的标記,否則在接收的時候為空,namespace與你制定的相同。
HolidayRequest.java代碼如下。
package com.chinamobile.cmss.eshub.ssb.wssimulator.entity;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "HolidayRequest", namespace="http://mycompany.com/hr/schemas")
@XmlAccessorType(XmlAccessType.FIELD)
public class HolidayRequest {
@XmlElement(namespace="http://mycompany.com/hr/schemas")
private Holiday Holiday;
@XmlElement(namespace="http://mycompany.com/hr/schemas")
private Employee Employee;
public Holiday getHoliday() {
return Holiday;
}
public void setHoliday(Holiday holiday) {
Holiday = holiday;
}
public Employee getEmployee() {
return Employee;
}
public void setEmployee(Employee employee) {
Employee = employee;
}
@Override
public String toString() {
return "HolidayRequest [Holiday=" + Holiday + ", Employee=" + Employee + "]";
}
}
在實體類相同的包下面建立
jaxb.properties
檔案,内容為
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
,表示我們不使用預設的JAXB,而是使用eclipselink提供的實作,使用預設的JAXB要寫更多的代碼配置ObjectFactory,否則會報
doesnt contain ObjectFactory.class or jaxb.index
的錯誤。
到此我們在官方執行個體的基礎上完成了一個更好用的樣例。