第三章. 編寫契約優先的 Web 服務

3.1. 簡介

本教程將向您展示如何編寫契約優先的 Web 服務,即先編寫 XML Schema/WSDL 契約,再編寫 Java 程式碼。Spring-WS 專注於這種開發風格,本教程將幫助您入門。請注意,本教程的第一部分幾乎不包含 Spring-WS 特定的資訊:它主要關於 XML、XSD 和 WSDL。第二部分則側重於使用 Spring-WS 實現此契約。

在進行契約優先的 Web 服務開發時,最重要的是嘗試用 XML 的方式思考。這意味著 Java 語言概念的重要性相對較低。透過網路傳輸的是 XML,您應該專注於此。Java 用於實現 Web 服務是一個實現細節。一個重要的細節,但仍然是細節。

在本教程中,我們將定義一個由人力資源部門建立的 Web 服務。客戶端可以向此服務傳送假期申請表來預訂假期。

3.2. 訊息

在本節中,我們將重點關注傳送到 Web 服務和從 Web 服務傳送的實際 XML 訊息。我們將從確定這些訊息的外觀開始。

3.2.1. 假期

在場景中,我們需要處理假期申請,因此確定假期在 XML 中是什麼樣子是有意義的

<Holiday xmlns="http://mycompany.com/hr/schemas">
    <StartDate>2006-07-03</StartDate>
    <EndDate>2006-07-07</EndDate>
</Holiday>

假期由開始日期和結束日期組成。我們還決定使用標準 ISO 8601 日期格式,因為這樣可以省去大量的解析麻煩。我們還在元素中添加了一個名稱空間,以確保我們的元素可以在其他 XML 文件中使用。

3.2.2. 員工

場景中還有一個員工的概念。下面是它在 XML 中的樣子

<Employee xmlns="http://mycompany.com/hr/schemas">
    <Number>42</Number>
    <FirstName>Arjen</FirstName>
    <LastName>Poutsma</LastName>
</Employee>

我們使用了與之前相同的名稱空間。如果此 <Employee/> 元素可以在其他場景中使用,那麼使用不同的名稱空間(例如 http://mycompany.com/employees/schemas)可能更有意義。

3.2.3. 假期申請

假期和員工元素都可以放入 <HolidayRequest/>

<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>

兩個元素的順序無關緊要:<Employee/> 也可以是第一個元素。重要的是所有資料都在那裡。事實上,資料是唯一重要的事情:我們正在採用資料驅動的方法。

3.3. 資料契約

既然我們已經看到了一些我們將要使用的 XML 資料示例,那麼將其形式化為模式是有意義的。此資料契約定義了我們接受的訊息格式。有四種不同的方式來定義 XML 的此類契約

DTDs 對名稱空間的支援有限,因此不適用於 Web 服務。Relax NG 和 Schematron 當然比 XML Schema 更容易。不幸的是,它們在各個平臺上並不廣泛支援。我們將使用 XML Schema。

到目前為止,建立 XSD 最簡單的方法是從示例文件推斷。任何好的 XML 編輯器或 Java IDE 都提供此功能。基本上,這些工具使用一些示例 XML 文件,並從中生成一個驗證所有這些文件的模式。最終結果肯定需要完善,但它是一個很好的起點。

使用上面描述的示例,我們得到了以下生成的模式

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
        elementFormDefault="qualified"
        targetNamespace="http://mycompany.com/hr/schemas"
        xmlns:hr="http://mycompany.com/hr/schemas">
    <xs:element name="HolidayRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="hr:Holiday"/>
                <xs:element ref="hr:Employee"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="Holiday">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="hr:StartDate"/>
                <xs:element ref="hr:EndDate"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="StartDate" type="xs:NMTOKEN"/>
    <xs:element name="EndDate" type="xs:NMTOKEN"/>
    <xs:element name="Employee">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="hr:Number"/>
                <xs:element ref="hr:FirstName"/>
                <xs:element ref="hr:LastName"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="Number" type="xs:integer"/>
    <xs:element name="FirstName" type="xs:NCName"/>
    <xs:element name="LastName" type="xs:NCName"/>
</xs:schema>

這個生成的模式顯然可以改進。首先要注意的是,每個型別都有一個根級別元素宣告。這意味著 Web 服務應該能夠接受所有這些元素作為資料。這是不可取的:我們只想接受一個 <HolidayRequest/>。透過刪除包裝元素標籤(從而保留型別)並內聯結果,我們可以實現這一點。

<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:sequence>
                <xs:element name="Holiday" type="hr:HolidayType"/>
                <xs:element name="Employee" type="hr:EmployeeType"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="HolidayType">
        <xs:sequence>
            <xs:element name="StartDate" type="xs:NMTOKEN"/>
            <xs:element name="EndDate" type="xs:NMTOKEN"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="EmployeeType">
        <xs:sequence>
            <xs:element name="Number" type="xs:integer"/>
            <xs:element name="FirstName" type="xs:NCName"/>
            <xs:element name="LastName" type="xs:NCName"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

模式仍然有一個問題:有了這樣的模式,您可以預期以下訊息會驗證

<HolidayRequest xmlns="http://mycompany.com/hr/schemas">
    <Holiday>
        <StartDate>this is not a date</StartDate>
        <EndDate>neither is this</EndDate>
    </Holiday>
    <!-- ... -->
</HolidayRequest>

顯然,我們必須確保開始日期和結束日期確實是日期。XML Schema 有一個出色的內建 date 型別,我們可以使用。我們還將 NCName 更改為 string。最後,我們將 <HolidayRequest/> 中的 sequence 更改為 all。這告訴 XML 解析器 <Holiday/><Employee/> 的順序無關緊要。我們最終的 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"/>                       (1)
                <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"/>                                  (2)
        </xs:sequence>                                                                   (2)
    </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"/>                               (3)
        </xs:sequence>                                                                   (3)
    </xs:complexType>
</xs:schema>

1

all 告訴 XML 解析器 <Holiday/><Employee/> 的順序無關緊要。

2

我們使用 xsd:date 資料型別,它由年、月和日組成,用於 <StartDate/><EndDate/>

3

xsd:string 用於名字和姓氏。

我們將此檔案儲存為 hr.xsd

3.4. 服務契約

服務契約通常表示為 WSDL 檔案。請注意,在 Spring-WS 中,不需要手動編寫 WSDL。根據 XSD 和一些約定,Spring-WS 可以為您建立 WSDL,如題為第 3.6 節,“實現端點”的章節中所述。如果您願意,可以跳到下一節;本節的其餘部分將向您展示如何手動編寫自己的 WSDL。

我們以標準的序言開始我們的 WSDL,並透過匯入我們現有的 XSD。為了將模式與定義分開,我們將為 WSDL 定義使用一個單獨的名稱空間:http://mycompany.com/hr/definitions

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
                  xmlns:schema="http://mycompany.com/hr/schemas"
                  xmlns:tns="http://mycompany.com/hr/definitions"
                  targetNamespace="http://mycompany.com/hr/definitions">
    <wsdl:types>
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <xsd:import namespace="http://mycompany.com/hr/schemas" schemaLocation="hr.xsd"/>
        </xsd:schema>
    </wsdl:types>

接下來,我們根據已編寫的模式型別新增訊息。我們只有一條訊息:一條包含我們在模式中放入的 <HolidayRequest/> 的訊息

    <wsdl:message name="HolidayRequest">
        <wsdl:part element="schema:HolidayRequest" name="HolidayRequest"/>
    </wsdl:message>

我們將訊息作為操作新增到埠型別中

    <wsdl:portType name="HumanResource">
        <wsdl:operation name="Holiday">
            <wsdl:input message="tns:HolidayRequest" name="HolidayRequest"/>
        </wsdl:operation>
    </wsdl:portType>

這完成了 WSDL 的抽象部分(介面),並留下了具體部分。具體部分由一個 binding 組成,它告訴客戶端如何呼叫您剛剛定義的操作;以及一個 service,它告訴客戶端在哪裡呼叫它。

新增具體部分是相當標準的:只需引用您之前定義的抽象部分,確保對 soap:binding 元素使用document/literalrpc/encoded 已棄用),為操作選擇一個 soapAction(在本例中為 http://mycompany.com/RequestHoliday,但任何 URI 都可以),並確定您希望請求傳入的 location URL(在本例中為 http://mycompany.com/humanresources

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
                  xmlns:schema="http://mycompany.com/hr/schemas"
                  xmlns:tns="http://mycompany.com/hr/definitions"
                  targetNamespace="http://mycompany.com/hr/definitions">
    <wsdl:types>
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <xsd:import namespace="http://mycompany.com/hr/schemas"                      (1)
                schemaLocation="hr.xsd"/>
        </xsd:schema>
    </wsdl:types>
    <wsdl:message name="HolidayRequest">                                                 (2)
        <wsdl:part element="schema:HolidayRequest" name="HolidayRequest"/>               (3)
    </wsdl:message>
    <wsdl:portType name="HumanResource">                                                 (4)
        <wsdl:operation name="Holiday">
            <wsdl:input message="tns:HolidayRequest" name="HolidayRequest"/>             (2)
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="HumanResourceBinding" type="tns:HumanResource">                  (4)(5)
        <soap:binding style="document"                                                   (6)
            transport="http://schemas.xmlsoap.org/soap/http"/>                           (7)
        <wsdl:operation name="Holiday">
            <soap:operation soapAction="http://mycompany.com/RequestHoliday"/>           (8)
            <wsdl:input name="HolidayRequest">
                <soap:body use="literal"/>                                               (6)
            </wsdl:input>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="HumanResourceService">
        <wsdl:port binding="tns:HumanResourceBinding" name="HumanResourcePort">          (5)
            <soap:address location="https://:8080/holidayService/"/>             (9)
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

1

我們匯入在第 3.3 節,“資料契約”中定義的模式。

2

我們定義了 HolidayRequest 訊息,它在 portType 中使用。

3

HolidayRequest 型別在模式中定義。

4

我們定義了 HumanResource 埠型別,它在 binding 中使用。

5

我們定義了 HumanResourceBinding 繫結,它在 port 中使用。

6

我們使用文件/文字樣式。

7

文字 http://schemas.xmlsoap.org/soap/http 表示 HTTP 傳輸。

8

soapAction 屬性表示將隨每個請求傳送的 SOAPAction HTTP 頭。

9

https://:8080/holidayService/ 地址是 Web 服務可以呼叫的 URL。

這是最終的 WSDL。我們將在下一節中描述如何實現生成的模式和 WSDL。

3.5. 建立專案

在本節中,我們將使用 Maven3 為我們建立初始專案結構。這樣做不是必需的,但大大減少了我們設定 HolidayService 所需編寫的程式碼量。

以下命令使用 Spring-WS 原型(即專案模板)為我們建立一個 Maven3 Web 應用程式專案

mvn archetype:create -DarchetypeGroupId=org.springframework.ws \
  -DarchetypeArtifactId=spring-ws-archetype \
  -DarchetypeVersion=2.1.4.RELEASE \
  -DgroupId=com.mycompany.hr \
  -DartifactId=holidayService

此命令將建立一個名為 holidayService 的新目錄。在此目錄中,有一個 'src/main/webapp' 目錄,其中將包含 WAR 檔案的根目錄。您將在此處找到標準的 Web 應用程式部署描述符 'WEB-INF/web.xml',它定義了一個 Spring-WS MessageDispatcherServlet 並將所有傳入請求對映到此 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>
    </servlet>

    <servlet-mapping>
        <servlet-name>spring-ws</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

除了上述 'WEB-INF/web.xml' 檔案,您還需要另一個 Spring-WS 特定配置檔案,名為 'WEB-INF/spring-ws-servlet.xml'。此檔案包含所有 Spring-WS 特定的 bean,例如 EndPointsWebServiceMessageReceivers 等,並用於建立新的 Spring 容器。此檔案的名稱派生自相應 servlet 的名稱(在本例中為 'spring-ws'),並附加 '-servlet.xml'。因此,如果您定義了一個名為 'dynamite'MessageDispatcherServlet,則 Spring-WS 特定配置檔案的名稱將是 'WEB-INF/dynamite-servlet.xml'

(您可以在???中檢視此示例的 'WEB-INF/spring-ws-servlet.xml' 檔案的內容。)

建立專案結構後,您可以將上一節中的模式和 wsdl 放入 'WEB-INF/' 資料夾中。

3.6. 實現端點

在 Spring-WS 中,您將實現端點來處理傳入的 XML 訊息。端點通常透過使用 @Endpoint 註解類來建立。在此端點類中,您將建立一個或多個處理傳入請求的方法。方法簽名可以非常靈活:您可以包含幾乎任何與傳入 XML 訊息相關的引數型別,具體將在後面解釋。

3.6.1. 處理 XML 訊息

在此示例應用程式中,我們將使用 JDom 來處理 XML 訊息。我們還使用 XPath,因為它允許我們選擇 XML JDOM 樹的特定部分,而不需要嚴格的模式一致性。

package com.mycompany.hr.ws;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
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.mycompany.hr.service.HumanResourceService;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.xpath.XPath;

@Endpoint                                                                                (1)
public class HolidayEndpoint {

  private static final String NAMESPACE_URI = "http://mycompany.com/hr/schemas";

  private XPath startDateExpression;

  private XPath endDateExpression;

  private XPath nameExpression;

  private HumanResourceService humanResourceService;

  @Autowired
  public HolidayEndpoint(HumanResourceService humanResourceService)                      (2)
      throws JDOMException {
    this.humanResourceService = humanResourceService;

    Namespace namespace = Namespace.getNamespace("hr", NAMESPACE_URI);

    startDateExpression = XPath.newInstance("//hr:StartDate");
    startDateExpression.addNamespace(namespace);

    endDateExpression = XPath.newInstance("//hr:EndDate");
    endDateExpression.addNamespace(namespace);

    nameExpression = XPath.newInstance("concat(//hr:FirstName,' ',//hr:LastName)");
    nameExpression.addNamespace(namespace);
  }

  @PayloadRoot(namespace = NAMESPACE_URI, localPart = "HolidayRequest")                  (3)
  public void handleHolidayRequest(@RequestPayload Element holidayRequest)               (4)
      throws Exception {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    Date startDate = dateFormat.parse(startDateExpression.valueOf(holidayRequest));
    Date endDate = dateFormat.parse(endDateExpression.valueOf(holidayRequest));
    String name = nameExpression.valueOf(holidayRequest);

    humanResourceService.bookHoliday(startDate, endDate, name);
  }

}

1

HolidayEndpoint@Endpoint 註解。這會將類標記為一種特殊的 @Component,適用於在 Spring-WS 中處理 XML 訊息,也使其符合元件掃描的條件。

2

HolidayEndpoint 需要 HumanResourceService 業務服務才能執行,因此我們透過建構函式注入依賴項並用 @Autowired 註解。接下來,我們使用 JDOM API 設定 XPath 表示式。有三個表示式://hr:StartDate 用於提取 <StartDate> 文字值,//hr:EndDate 用於提取結束日期,concat(//hr:FirstName,' ',//hr:LastName) 用於提取並連線員工姓名。

3

@PayloadRoot 註解告訴 Spring-WS handleHolidayRequest 方法適用於處理 XML 訊息。此方法可以處理的訊息型別由註解值指示,在這種情況下,它可以處理具有 HolidayRequest 本地部分和 http://mycompany.com/hr/schemas 名稱空間的 XML 元素。有關將訊息對映到端點的更多資訊,請參閱下一節。

4

handleHolidayRequest(..) 方法是主要的處理方法,它接收來自傳入 XML 訊息的 <HolidayRequest/> 元素。@RequestPayload 註解表示 holidayRequest 引數應對映到請求訊息的有效載荷。我們使用 XPath 表示式從 XML 訊息中提取字串值,並使用 SimpleDateFormat 將這些值轉換為 Date 物件。使用這些值,我們呼叫業務服務上的一個方法。通常,這將導致資料庫事務開始,並且資料庫中的一些記錄被更改。最後,我們定義了一個 void 返回型別,這向 Spring-WS 表明我們不想傳送響應訊息。如果我們想要響應訊息,我們可以返回一個表示響應訊息有效載荷的 JDOM 元素。

使用 JDOM 只是處理 XML 的一種選擇:其他選擇包括 DOM、dom4j、XOM、SAX 和 StAX,以及 JAXB、Castor、XMLBeans、JiBX 和 XStream 等編組技術,如下一章所述。我們選擇 JDOM 是因為它允許我們訪問原始 XML,並且因為它基於類(而不是像 W3C DOM 和 dom4j 那樣的介面和工廠方法),這使得程式碼更簡潔。我們使用 XPath 是因為它比編組技術更不脆弱:我們不關心嚴格的模式一致性,只要我們能找到日期和姓名。

因為我們使用 JDOM,所以我們必須向 Maven pom.xml(位於專案目錄的根目錄)新增一些依賴項。以下是 POM 的相關部分

<dependencies>
    <dependency>
        <groupId>org.springframework.ws</groupId>
        <artifactId>spring-ws-core</artifactId>
        <version>2.1.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>jdom</groupId>
        <artifactId>jdom</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>jaxen</groupId>
        <artifactId>jaxen</artifactId>
        <version>1.1</version>
    </dependency>
</dependencies>

以下是我們如何在 spring-ws-servlet.xml Spring XML 配置檔案中使用元件掃描來配置這些類。我們還透過 <sws:annotation-driven> 元素指示 Spring-WS 使用註解驅動的端點。

<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.mycompany.hr"/>

  <sws:annotation-driven/>

</beans>

3.6.2. 將訊息路由到端點

在編寫端點時,我們還使用了 @PayloadRoot 註解來指示 handleHolidayRequest 方法可以處理哪種型別的訊息。在 Spring-WS 中,此過程由 EndpointMapping 負責。我們在此處透過使用 PayloadRootAnnotationMethodEndpointMapping 根據訊息內容路由訊息。上面使用的註解

@PayloadRoot(namespace = "http://mycompany.com/hr/schemas", localPart = "HolidayRequest")

基本上意味著每當收到具有名稱空間 http://mycompany.com/hr/schemas 和本地名稱 HolidayRequest 的 XML 訊息時,它都將被路由到 handleHolidayRequest 方法。透過在我們的配置中使用 <sws:annotation-driven> 元素,我們啟用了 @PayloadRoot 註解的檢測。在一個端點中可以有多個相關的處理方法,每個方法處理不同的 XML 訊息,這是可能的(並且很常見)。

還有其他將端點對映到 XML 訊息的方法,將在下一章中描述。

3.6.3. 提供服務和存根實現

現在我們有了端點,我們需要 HumanResourceService 及其實現供 HolidayEndpoint 使用。

package com.mycompany.hr.service;

import java.util.Date;

public interface HumanResourceService {
    void bookHoliday(Date startDate, Date endDate, String name);
}

出於教程目的,我們將使用 HumanResourceService 的一個簡單存根實現。

package com.mycompany.hr.service;

import java.util.Date;

import org.springframework.stereotype.Service;

@Service                                                                                 (1)
public class StubHumanResourceService implements HumanResourceService {
    public void bookHoliday(Date startDate, Date endDate, String name) {
        System.out.println("Booking holiday for [" + startDate + "-" + endDate + "] for [" + name + "] ");
    }
}

1

StubHumanResourceService@Service 註解。這會將類標記為業務外觀,使其成為 HolidayEndpoint@Autowired 注入的候選物件。

3.7. 釋出 WSDL

最後,我們需要釋出 WSDL。如第 3.4 節,“服務契約”所述,我們不需要自己編寫 WSDL;Spring-WS 可以根據一些約定為我們生成 WSDL。以下是我們定義生成的方式

<sws:dynamic-wsdl id="holiday"                                                           (1)
    portTypeName="HumanResource"                                                         (3)
    locationUri="/holidayService/"                                                       (4)
    targetNamespace="http://mycompany.com/hr/definitions">                               (5)
  <sws:xsd location="/WEB-INF/hr.xsd"/>                                                  (2)
</sws:dynamic-wsdl>

1

id 決定了可以檢索 WSDL 的 URL。在這種情況下,id 是 holiday,這意味著 WSDL 可以在 servlet 上下文中以 holiday.wsdl 的形式檢索。完整的 URL 通常是 https://:8080/holidayService/holiday.wsdl

3

接下來,我們將 WSDL 埠型別設定為 HumanResource

4

我們設定了服務可訪問的位置:/holidayService/。我們使用相對 URI,並指示框架將其動態轉換為絕對 URI。因此,如果服務部署到不同的上下文,我們無需手動更改 URI。有關更多資訊,請參閱第 5.3.1.1 節,“自動 WSDL 暴露”

為了使位置轉換生效,我們需要在 web.xml 中為 spring-ws servlet 新增一個 init 引數

<init-param>
  <param-name>transformWsdlLocations</param-name>
  <param-value>true</param-value>
</init-param>

5

我們定義 WSDL 定義本身的目標名稱空間。設定此屬性不是必需的。如果未設定,WSDL 將與 XSD 模式具有相同的名稱空間。

2

xsd 元素引用了我們在第 3.3 節,“資料契約”中定義的人力資源模式。我們只是將模式放在應用程式的 WEB-INF 目錄中。

您可以使用 mvn install 建立一個 WAR 檔案。如果您將應用程式部署(到 Tomcat、Jetty 等),並將瀏覽器指向此位置,您將看到生成的 WSDL。此 WSDL 已準備好供客戶端使用,例如 soapUI 或其他 SOAP 框架。

本教程到此結束。本教程程式碼可在 Spring-WS 的完整發行版中找到。下一步是檢視發行版中包含的 echo 示例應用程式。之後,檢視 airline 示例,它稍微複雜一些,因為它使用 JAXB、WS-Security、Hibernate 和事務性服務層。最後,您可以閱讀其餘的參考文件。

© . This site is unofficial and not affiliated with VMware.