WSDL 樣式
對于剛剛學習 WSDL 的開發人員而言,最容易混淆的是為文檔選擇樣式。讓我們了解一下不同的選項及其對 WSDL 和 SOAP 文檔的影響。
在 XML 世界中,通常有兩種類型的人:將 XML 視為數據格式的人和將 XML 視為文檔標記的人。通常,二者永遠對立。在某種程度上,這種對立也進入了 Web 服務中。有人將其視為基于 XML 的遠程過程調用 (Remote Procedure Call),還有些人將其視為將 XML 信息從一個位置傳遞到另一個位置的方法。
對 WSDL 而言,這會在選擇消息的“樣式”時表現出來。創建綁定時,可以選擇 Document 樣式(如 Larry 為 Classifieds 服務就是選擇的此樣式)或 RPC 樣式。這兩個樣式并不一定就“正確”或“錯誤”。但二者均具有自己的優點和缺點。
使用 RPC 樣式時,要執行的方法的名稱同時也是有效負載的根元素的名稱。您可能會說,等一等。Classifieds WSDL 的結構不就是這樣嗎?是,也不是。之所以說是,是因為根元素的名稱與我們希望服務執行的方法的名稱一樣。不過,從某種意義而言,這只是巧合;Larry 是有意這樣設計服務的。
讓我們看看不同的選擇及其在 WSDL 和 SOAP 方面的表現。
Document/Literal 樣式意味著有效負載僅包含要向服務傳遞的實際數據。任何將消息發送到其目的地所必需的路由均以其他方式來完成,如通過 soapAction
Header 或服務的特定 URL。
這樣的消息簡單而直接(請參見清單 27)。
清單 27. Document/Literal 消息
<env:Envelope
xmlns:env="http://schemas.xmlSOAP.org/SOAP/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<req:content>Vintage 1963 T-Bird...</req:content>
<req:endDate>4/30/07</req:endDate>
</env:Body>
</env:Envelope>
|
請注意,有效負載沒有根元素。在 WSDL 文件中,您直接定義相應的元素并將其添加到消息中(請參見清單 28)。
清單 28. Document/Literal WSDL
... <wsdl:types> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://org.apache.axis2/xsd" elementFormDefault="unqualified" attributeFormDefault="unqualified"> ... <xs:element type="xs:string" name="content" /> <xs:element type="xs:string" name="endDate" /> ... </xs:schema> </wsdl:types> <wsdl:message name="createNewAdRequestMessage"> <wsdl:part name="part1" element="ns1:content" /> <wsdl:part name="part2" element="ns1:endDate" /> </wsdl:message> ... <wsdl:portType name="ClassifiedServicePortType"> ... <wsdl:operation name="createNewAd"> <wsdl:input message="tns:createNewAdRequestMessage" /> <wsdl:output message="tns:createNewAdResponseMessage" /> </wsdl:operation> ... </wsdl:portType> ... <wsdl:binding name="ClassifiedServiceBinding" type="tns:ClassifiedServicePortType"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <wsdl:operation name="createNewAd"> <soap:operation soapAction="createNewAd" style="document" /> <wsdl:input> <soap:body use="literal" /> </wsdl:input> <wsdl:output> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> ... </wsdl:binding> ... |
請注意,在 Document 樣式中,屬于有效負載的所有元素都在模式中具有相應的定義。另請注意,此消息具有兩個截然不同的部分,每個部分各自引用一個特定的元素。
![]() ![]() |
![]()
|
本教程使用 Document/Literal/Wrapped 樣式。此樣式與 Document/Literal 樣式類似,不過其有效負載具有根元素。這具有包含要執行的方法的名稱的優點(雖然這并不是必需的),同時也符合 WS-I 基本概要的要求。為了便于理解,下面提供了一個簡單的消息(請參見清單 29)。
清單 29. Document/Literal/Wrapped 消息
<env:Envelope xmlns:env="http://schemas.xmlSOAP.org/SOAP/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <env:Body> <req:createNewAdRequest xmlns:req="http://daily-moon.com/classifieds/"> <req:content>Vintage 1963 T-Bird...</req:content> <req:endDate>4/30/07</req:endDate> </req:createNewAdRequest> </env:Body> </env:Envelope> |
為了保持完整性,下面提供了相關的 WSDL(請參見清單 30)。
清單 30. Document/literal/Wrapped WSDL
... <wsdl:types> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://org.apache.axis2/xsd" elementFormDefault="unqualified" attributeFormDefault="unqualified"> ... <xs:element name="createNewAdRequest"> <xs:complexType> <xs:sequence> <xs:element type="xs:string" name="content" /> <xs:element type="xs:string" name="endDate" /> </xs:sequence> </xs:complexType> </xs:element> ... </xs:schema> </wsdl:types> <wsdl:message name="createNewAdRequestMessage"> <wsdl:part name="part1" element="ns1:createNewAdRequest" /> </wsdl:message> ... <wsdl:portType name="ClassifiedServicePortType"> <wsdl:operation name="createNewAd"> <wsdl:input message="tns:createNewAdRequestMessage" /> <wsdl:output message="tns:createNewAdResponseMessage" /> </wsdl:operation> ... </wsdl:portType> ... <wsdl:binding name="ClassifiedServiceBinding" type="tns:ClassifiedServicePortType"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <wsdl:operation name="createNewAd"> <soap:operation soapAction="createNewAd" style="document" /> <wsdl:input> <soap:body use="literal" namespace="http://ws.apache.org/axis2" /> </wsdl:input> <wsdl:output> <soap:body use="literal" namespace="http://ws.apache.org/axis2" /> </wsdl:output> </wsdl:operation> ... </wsdl:binding> ... |
同樣,有效負載中的所有元素都在模式中定義。
![]() ![]() |
![]()
|
RPC 樣式進行處理的方式略為不同。進入消息中的是 WSDL 的相應內容,而不是模式中的內容。例如,請看以下的 SOAP 消息(請參見清單 31)。
清單 31. RPC/Literal 消息
<env:Envelope xmlns:env="http://schemas.xmlSOAP.org/SOAP/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <env:Body> <req:createNewAdRequest xmlns:req="http://daily-moon.com/classifieds/"> <req:content>Vintage 1963 T-Bird...</req:content> <req:endDate>4/30/07</req:endDate> </req:createNewAdRequest> </env:Body> </env:Envelope> |
消息本身與 Document/Literal/Wrapped 樣式一樣,但 WSDL 大不相同(請參見清單 32)。
清單 32. RPC/Literal 消息的 WSDL
... <wsdl:types> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://org.apache.axis2/xsd" elementFormDefault="unqualified" attributeFormDefault="unqualified"> ... </xs:schema> </wsdl:types> <wsdl:message name="createNewAdRequest"> <wsdl:part name="content " element=" xsd:string" /> <wsdl:part name="endDate " element=" xsd:string" /> </wsdl:message> ... <wsdl:portType name="ClassifiedServicePortType"> <wsdl:operation name="createNewAd"> <wsdl:input message="tns:createNewAdRequest" /> <wsdl:output message="tns:createNewAdResponseMessage" /> </wsdl:operation> ... </wsdl:portType> ... <wsdl:binding name="ClassifiedServiceBinding" type="tns:ClassifiedServicePortType"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <wsdl:operation name="createNewAd"> <soap:operation soapAction="createNewAd" style="rpc" /> <wsdl:input> <soap:body use="literal" namespace="http://ws.apache.org/axis2" /> </wsdl:input> <wsdl:output> <soap:body use="literal" namespace="http://ws.apache.org/axis2" /> </wsdl:output> </wsdl:operation> ... </wsdl:binding> ... |
首先,請注意模式中并未定義任何實際內容。相反,message
指定要執行的方法的名稱,而 message part
直接定義每個元素。另請注意,在 RPC 樣式中,消息部分的名稱很重要;此名稱是有效負載內的元素的名稱。消息類型是直接定義的。(當然,這意味著您無法在有效負載中包含復雜元素,但由于此樣式用于模擬遠程過程調用,因此這并不是一個問題。)
在 portType
中,當您指定消息時,可以直接引用與這些元素一起創建的消息。然后,在綁定中,通過指定 RPC 樣式,可以清楚地確定如何將所有這些內容轉換為 SOAP 消息。
![]() ![]() |
![]()
|
我們要了解的最后一個樣式是 RPC/Encoded。此樣式與 RPC/Literal 類似,唯一的不同之處在于由 SOAP 消息定義實際類型信息(請參見清單 33)。
清單 33. RPC/Encoded SOAP 消息
<env:Envelope xmlns:env="http://schemas.xmlSOAP.org/SOAP/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <env:Body> <req:createNewAdRequest xmlns:req="http://daily-moon.com/classifieds/"> <req:content xsi:type="xs:string">Vintage 1963 T-Bird...</req:content> <req:endDate xsi:type="xs:string">4/30/07</req:endDate> </req:createNewAdRequest> </env:Body> </env:Envelope> |
用于定義此消息的 WSDL 與 RPC/Literal 一樣,但向綁定添加了額外的編碼信息(請參見清單 34)。
清單 34. RPC/Encoded WSDL
<wsdl:definitions xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://ws.apache.org/axis2" xmlns:axis2="http://ws.apache.org/axis2" xmlns:ns1="http://org.apache.axis2/xsd" targetNamespace="http://ws.apache.org/axis2"> <wsdl:types> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://org.apache.axis2/xsd" elementFormDefault="unqualified" attributeFormDefault="unqualified"> ... </xs:schema> </wsdl:types> <wsdl:message name="createNewAdRequest"> <wsdl:part name="content" element="xsd:string" /> <wsdl:part name="endDate" element="xsd:string" /> </wsdl:message> ... <wsdl:portType name="ClassifiedServicePortType"> <wsdl:operation name="createNewAd"> <wsdl:input message="tns:createNewAdRequest" /> <wsdl:output message="tns:createNewAdResponse" /> </wsdl:operation> ... </wsdl:portType> <wsdl:binding name="ClassifiedServiceBinding" type="tns:ClassifiedServicePortType"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc" /> <wsdl:operation name="createNewAd"> <soap:operation soapAction="createNewAd" style="document" /> <wsdl:input> <soap:body use="encoded" encodingStyle=http://schemas.xmlsoap.org/soap/encoding/ namespace="http://ws.apache.org/axis2" /> </wsdl:input> <wsdl:output> <soap:body use="literal" namespace= "http://ws.apache.org/axis2" /> </wsdl:output> </wsdl:operation> ... </wsdl:binding> ... |
手動創建 WSDL 文件時,必須自己處理其中的所有內容。幸運的是,并不一定始終要手動進行創建。
![]() ![]() |
![]()
|
使用 WSDL 生成代碼
Gene 和 Francis 是該報社的團隊程序員,借調自 IT 部門,Classifieds Department 可以隨時調請他們處理自己的項目。他們將通過采用兩種方法來進行生成 WSDL 代碼的工作;Gene 將重點進行從 Java 到 WSDL 的代碼生成工作,而 Francis 將從 WSDL 生成 Java 代碼。
在 WSDL 的早期,最先出現的兩個應用程序是 Java2WSDL 和 WSDL2Java。那么,不能用來實現自動化功能的自動化格式究竟有什么好處呢?當然,當時您的選擇是有限的。這些代碼最初是面向 RPC 樣式的,很難自動生成帶復雜有效負載的系統。
很快發展到了目前的階段,這些問題得到了很好的解決。Axis2 幾乎可以從任何 WSDL 文檔生成 Java 代碼,也能從 WSDL 生成 Java 類。它通過數據綁定實現了這個目標,在數據綁定中,XML 結構可以轉換為 Java 對象,反之亦然。此生成過程將創建代碼,以供隨后進行更改、調整、編譯和運行。
首先,Gene 從 Java 類開始,使用其生成 WSDL 文檔。然后,Francis 獲取該文檔,并使用其生成服務和客戶機。對于服務,此生成過程將創建一個框架,可以在其中添加自己的代碼,以執行希望服務執行的操作。對于客戶機,它將創建一個存根,以用于像使用 Java 方法一樣調用 Web 服務方法。
第一步要確保環境已經準備就緒。下載 Apache Axis2 的 0.95 版,對其進行解壓縮,然后確保 lib 目錄中的所有其他 *.jar 文件都位于 CLASSPATH 上。
要運行 Web 服務,請安裝 Apache Geronimo(如果尚未安裝)并將其啟動。(具體說明,請參見第 1 部分。)下載 Axis2 v0.95 War 分發版并將其復制到 <GERONIMO_HOME>/deploy 目錄。Geronimo 將自動部署 Axis2。
![]() ![]() |
![]()
|
Gene 從 ClassifiedService
類著手,他會將此類作為主服務,同時也作為進行測試的方法,以確保所有部分均按預期工作(請參見清單 35)。
清單 35. ClassifiedService.java
package org.dailymoon.classifieds; public class ClassifiedService { public static int createNewAd(String content, String endDate){ ClassifiedAd newAd = new ClassifiedAd(); newAd.setEnd(endDate); newAd.setContent(content); newAd.save(); return 1; } public static boolean editExistingAd(ClassifiedAd adToEdit){ //Do stuff with the ad here return true; } public static ClassifiedList getExistingAds(){ ClassifiedAd[] listOfAds = {new ClassifiedAd(), new ClassifiedAd(), new ClassifiedAd()}; ClassifiedList listToReturn = new ClassifiedList(listOfAds); return listToReturn; } public static void finalizeIssue(String dateToFinalize){ //Don't return anything. System.out.println(dateToFinalize + " finalized."); } public static void main (String args[]){ ClassifiedService.createNewAd( "Eclipse experts needed. Contact Nick for details.", "4/21/2006"); ClassifiedAd adToEdit = new ClassifiedAd(); adToEdit.setId(1); adToEdit.setStart("4/8/2006"); adToEdit.setEnd("4/30/2006"); adToEdit.setContent( "Geronimo experts needed. Contact Nick for details."); ClassifiedService.editExistingAd(adToEdit); ClassifiedList adList = ClassifiedService.getExistingAds(); System.out.println(adList.toString()); } } |
此應用程序本身相當簡單。它提供了創建新廣告、編輯現有廣告和列出現有廣告的示例。它提供了對 Gene 希望公開的四個方法(createNewAd
、editExistingAd
、getExistingAds
和 finalizeIssue
)的基本限制。
(請確保在生成 WSDL 前將 main 方法注釋掉。此方法不會有負作用,但會生成不必要的額外代碼。)
此類還引用其他兩個類 ClassifiedAd
和 ClassifiedList
。為了生成過程能夠了解如何將這些對象構建為 XML 結構,Gene 將其創建為獨立的類(請參見清單 36)。
清單 36. ClassifiedAd.java
package org.dailymoon.classifieds; public class ClassifiedAd { private int id; private String startDate; private String endDate; private String content; public void setId(int newId){ id = newId; } public void setStartDate(String newStart){ startDate = newStart; } public void setEndDate(String newEnd){ endDate = newEnd; } public void setContent(String newContent){ content = newContent; } public void save(){ //Save data here System.out.println("Ad saved."); } } |
同樣,類本身并不完整,但已經具有了相應的結構(請參見清單 37)。
清單 37. ClassifiedList.java
package org.dailymoon.classifieds; public class ClassifiedList { public ClassifiedAd[] listOfAds; public ClassifiedList(ClassifiedAd[] newListOfAds){ listOfAds = newListOfAds; } public ClassifiedAd[] getRawAds(){ return listOfAds; } public String toString(){ return "This is a string of results."; } } |
此處,Gene 指定 ClassifiedList
包含一個 ClassifiedAd
對象數組。
有了所有這些類后,他就可以生成 WSDL 了。
![]() ![]() |
![]()
|
創建 WSDL 是一個簡單的過程。Gene 從命令行發出相應的命令,如清單 38 中所示:
清單 38. 用于生成 WSDL 的命令
java org.apache.axis2.wsdl.Java2WSDL -cn org.dailymoon.classifieds.ClassifiedService -o |
(請注意,此命令應該全部在一行輸入。)
-cn
開關指定形成服務基礎的類。-o
開關指定輸出目錄。如果沒有出現問題,此類將以靜默方式執行,在輸出文件中生成 ClassifiedService.wsdl 文件。此文件與 Larry 前面生成的文件很相似——它們設計為在相同的服務上工作——但需要進行一些小更改,以調整生成過程中采用一般方式命名的項。具體來說,不一定始終正確地進行參數轉換,將可能必須進行重命名。
以下是生成的 WSDL 文件,其中調整的部分以黑體顯示(請參見清單 39)。
清單 39. WSDL 文件
<wsdl:definitions xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://ws.apache.org/axis2" xmlns:ns1="http://org.apache.axis2/xsd" targetNamespace="http://ws.apache.org/axis2"> <wsdl:types> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://org.apache.axis2/xsd" elementFormDefault="unqualified" attributeFormDefault="unqualified"> <xs:element type="ns1:ClassifiedAd" name="ClassifiedAd" /> <xs:complexType name="ClassifiedAd"> <xs:sequence> <xs:element type="xs:int" name="id" /> <xs:element type="xs:string" name="content" /> <xs:element type="xs:string" name="endDate" /> <xs:element type="xs:string" name="startDate" /> </xs:sequence> </xs:complexType> <xs:element type="ns1:ClassifiedList" name="ClassifiedList" /> <xs:complexType name="ClassifiedList"> <xs:sequence> <xs:element minOccurs="0" type="ns1:ClassifiedAd" name="ClassifiedAd" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> <xs:element name="createNewAdRequest"> <xs:complexType> <xs:sequence> <xs:element type="xs:string" name="content" /> <xs:element type="xs:string" name="endDate" /> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="createNewAdResponse"> <xs:complexType> <xs:sequence> <xs:element type="xs:int" name="newAdId" /> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="editExistingAdRequest"> <xs:complexType> <xs:sequence> <xs:element type="ns1:ClassifiedAd" name="existingAd" /> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="editExistingAdResponse"> <xs:complexType> <xs:sequence> <xs:element type="xs:boolean" name=" wasSuccessful"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="getExistingAdsRequest"> <xs:complexType /> </xs:element> <xs:element name="getExistingAdsResponse"> <xs:complexType> <xs:sequence> <xs:element type="ns1:ClassifiedList" name="ClassifiedList" /> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="finalizeIssueRequest"> <xs:complexType> <xs:sequence> <xs:element type="xs:string" name="issueToFinalize" /> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> </wsdl:types> <wsdl:message name="createNewAdRequestMessage"> <wsdl:part name="part1" element="ns1:createNewAdRequest" /> </wsdl:message> <wsdl:message name="createNewAdResponseMessage"> <wsdl:part name="part1" element="ns1:createNewAdResponse" /> </wsdl:message> <wsdl:message name="getExistingAdsResponseMessage"> <wsdl:part name="part1" element="ns1:getExistingAdsResponse" /> </wsdl:message> <wsdl:message name="editExistingAdRequestMessage"> <wsdl:part name="part1" element="ns1:editExistingAdRequest" /> </wsdl:message> <wsdl:message name="getExistingAdsRequestMessage"> <wsdl:part name="part1" element="ns1:getExistingAdsRequest" /> </wsdl:message> <wsdl:message name="editExistingAdResponseMessage"> <wsdl:part name="part1" element="ns1:editExistingAdResponse" /> </wsdl:message> <wsdl:message name="finalizeIssueRequestMessage"> <wsdl:part name="part1" element="ns1:finalizeIssueRequest" /> </wsdl:message> <wsdl:portType name="ClassifiedServicePortType"> <wsdl:operation name="finalizeIssue"> <wsdl:input message="tns:finalizeIssueRequestMessage" /> </wsdl:operation> <wsdl:operation name="createNewAd"> <wsdl:input message="tns:createNewAdRequestMessage" /> <wsdl:output message="tns:createNewAdResponseMessage" /> </wsdl:operation> <wsdl:operation name="editExistingAd"> <wsdl:input message="tns:editExistingAdRequestMessage" /> <wsdl:output message="tns:editExistingAdResponseMessage" /> </wsdl:operation> <wsdl:operation name="getExistingAds"> <wsdl:input message="tns:getExistingAdsRequestMessage" /> <wsdl:output message="tns:getExistingAdsResponseMessage" /> </wsdl:operation> </wsdl:portType> <wsdl:binding name="ClassifiedServiceBinding" type="tns:ClassifiedServicePortType"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <wsdl:operation name="createNewAd"> <soap:operation soapAction="createNewAd" style="document" /> <wsdl:input> <soap:body use="literal" namespace="http://daily-moon.com/classifieds" /> </wsdl:input> <wsdl:output> <soap:body use="literal" namespace="http://daily-moon.com/classifieds" /> </wsdl:output> </wsdl:operation> <wsdl:operation name="finalizeIssue"> <soap:operation soapAction="finalizeIssue" style="document" /> <wsdl:input> <soap:body use="literal" namespace="http://daily-moon.com/classifieds" /> </wsdl:input> </wsdl:operation> <wsdl:operation name="editExistingAd"> <soap:operation soapAction="editExistingAd" style="document" /> <wsdl:input> <soap:body use="literal" namespace="http://daily-moon.com/classifieds" /> </wsdl:input> <wsdl:output> <soap:body use="literal" namespace="http://daily-moon.com/classifieds" /> </wsdl:output> </wsdl:operation> <wsdl:operation name="getExistingAds"> <soap:operation soapAction="getExistingAds" style="document" /> <wsdl:input> <soap:body use="literal" namespace="http://daily-moon.com/classifieds" /> </wsdl:input> <wsdl:output> <soap:body use="literal" namespace="http://daily-moon.com/classifieds" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="ClassifiedService"> <wsdl:port name="ClassifiedServicePort" binding="tns:ClassifiedServiceBinding"> <soap:address location= "http://127.0.0.1:8080/axis2/services/ClassifiedService" /> </wsdl:port> </wsdl:service> </wsdl:definitions> |
其中的大部分更改都只是為了方便或提供易用性;“content”要比“param0”好記得多。其中的兩個更改——頂部的命名空間和底部的命名空間前綴——是由于 Axis2 的 0.95 版中的兩個小軟件錯誤而需要進行的,在您閱讀本文時,可能已經不再需要這樣處理了。
![]() ![]() |
![]()
|
有了 WSDL 文件后,Francis 就可以使用其生成服務和客戶機。(實際上,Francis 可以直接使用 Larry 生成的版本。)
Francis 首先生成服務器端的代碼,如清單 40 中所示:
清單 40. 服務器端代碼
java org.apache.axis2.wsdl.WSDL2Java -uri ClassifiedService.wsdl -ss -sd -p org.dailymoon.classifieds -d xmlbeans -o service |
(同樣,請在一行輸入此命令。)
第一個參數是 WSDL 文件的 URL。當然,您可以使用此應用程序訪問遠程文件。第二個開關 -ss
告知應用程序生成服務(而不是客戶機)。-sd
開關告知應用程序生成 XML 服務描述符,從而更便于在生成服務代碼后進行部署。下一個參數當然是包,其后緊跟數據綁定方法??捎玫姆椒ㄓ?adb
、xmlbeans
和 jaxme
。最后,為了保持條理清楚,Francis 將服務生成到名為 source 的新目錄中。
所得到的結果是數百個文件。幸運的是,您只需要處理其中的一個即可。
![]() ![]() |
![]()
|
盡管在本例中,服務是從 WSDL 文件生成,而該文件本身又是從 Java 類生成的,但生成的代碼中并沒有實際的邏輯。其中僅包含相應的結構。為了讓服務實際進行一些工作,需要對框架文件進行編輯。
在此結構中,要處理的文件如清單 41 中所示:
清單 41. 從 Java 類生成的文件
service\src\org\dailymoon\classifieds\ClassifiedServicePortTypeSkeleton. java |
此代碼中包含大量注釋,當嘗試自己進行配置時,這些注釋就非常有用;但需要對其進行說明時,就很容易帶來干擾。下面是經過清理的版本,并包含為了實現部分服務而添加的代碼(請參見清單 42)。
清單 42. ClassifiedServicePortTypeSkeleton.java
package org.dailymoon.classifieds; public class ClassifiedServicePortTypeSkeleton { public axis2.apache.org.xsd.CreateNewAdResponseDocument createNewAd (axis2.apache.org.xsd.CreateNewAdRequestDocument param0 ) throws Exception { //Todo fill this with the necessary business logic //throw new java.lang.UnsupportedOperationException(); System.out.println("New ad requested, to end on " + param0.getCreateNewAdRequest().getEndDate()); System.out.println( param0.getCreateNewAdRequest().getContent()); axis2.apache.org.xsd.CreateNewAdResponseDocument responseDoc = axis2.apache.org.xsd.CreateNewAdResponseDocument .Factory.newInstance(); axis2.apache.org.xsd.CreateNewAdResponseDocument .CreateNewAdResponse response = responseDoc.addNewCreateNewAdResponse(); response.setNewAdId(1138); return responseDoc; } public void finalizeIssue (axis2.apache.org.xsd.FinalizeIssueRequestDocument param2) throws Exception { //Todo fill this with the necessary business logic } public axis2.apache.org.xsd.EditExistingAdResponseDocument editExistingAd (axis2.apache.org.xsd.EditExistingAdRequestDocument param3) throws Exception { //Todo fill this with the necessary business logic throw new java.lang.UnsupportedOperationException(); } public axis2.apache.org.xsd.GetExistingAdsResponseDocument getExistingAds (axis2.apache.org.xsd.GetExistingAdsRequestDocument param5) throws Exception { //Todo fill this with the necessary business logic throw new java.lang.UnsupportedOperationException(); } } |
在實際實現方法前,每個方法都會引發 UnsupportedOperationException
。為了將數據提交到服務,請首先處理參數和獲得請求本身。這樣,就可以使用 getter 方法來提取各個成員了。
顯然,在實際的服務中,您希望進行的不僅是輸出文本,而 Francis 僅是為了確保此服務能夠正常工作。要創建響應,請從恰當的響應文檔著手,通過類的 Factory
獲得一個實例。(類本身非常復雜,包含大量內部類,但有必要了解一下它的結構。)獲得了此文檔后,請創建實際響應本身,并將其添加到此文檔中。
可以通過使用 setter 方法在響應上設置值。直接返回響應文檔,支持類負責將其發送回請求方。
![]() ![]() |
![]()
|
為了部署服務,您需要對其進行編譯,并將其轉換為 Axis2 存檔文件。首先編譯和打包服務,如清單 43 中所示。
清單 43. 打包服務
set ANT_HOME=e:\apache-ant-1.6.5 PATH=%PATH%;%ANT_HOME%\bin; set AXIS2_HOME=e:\axis2 cd service ant jar.service |
對于非 Windows 安裝,請對所用語法進行恰當調整,并確保使用的是實際文件位置。
此 Ant 任務將編譯所有相應的文件,并創建兩個存檔文件 ClassifiedService.aar 和 XBeans-packaged.jar,這兩個文件都位于 build/lib 目錄中。
要部署服務,請確保 Geronimo 正在運行,并將瀏覽器指向清單 44 中所示的位置:
清單 44. 部署服務
http://localhost:8080/axis2/Login.jsp |
使用憑據 admin/axis2 登錄,并單擊 Upload Service>Browse。導航到 ClassifiedService.aar 文件,然后單擊 OK。單擊 Upload,以完成此過程。
如果單擊 View Services,應該看到列出了新服務。
![]() ![]() |
![]()
|
現在剩下任務就是生成用于訪問新服務的客戶機。為此,請從命令行執行以下命令:
清單 45. 用于生成客戶機的命令
java org.apache.axis2.wsdl.WSDL2Java -uri ClassifiedService.wsdl -p org.dailymoon.classifieds -d xmlbeans -o client |
同樣,這也是單個命令,需要在單行中輸入。相應的參數和服務器端代碼生成幾乎完全相同,不過不需要服務描述符。另外,為了保持條理性,Francis 將新文件放入了獨立的 client 目錄中。
這個類應該以靜默方式執行,在調用時會生成數百個文件,但您并不需要直接處理其中的任何文件。
![]() ![]() |
![]()
|
代碼生成過程并不會實際創建客戶機,但會創建一個類,可以利用此類方便地創建客戶機。為了簡化編譯,Francis 在 client\src\org\dailymoon\classifieds 目錄中創建了一個名為 Client.java 的新類文件。這樣, Ant 就會選取 .java 文件,并將其與其他源文件一起編譯。
Francis 添加了清單 46 中的代碼。
清單 46. 客戶機
package org.dailymoon.classifieds; import axis2.apache.org.xsd.*; public class Client{ public static void main(java.lang.String args[]){ try{ ClassifiedServicePortTypeStub stub = new ClassifiedServicePortTypeStub(null, "http://localhost:8080/axis2/services/ClassifiedService"); CreateNewAdRequestDocument cnaDoc = CreateNewAdRequestDocument.Factory.newInstance(); CreateNewAdRequestDocument.CreateNewAdRequest cnaReq = cnaDoc.addNewCreateNewAdRequest(); cnaReq.setContent("Vintage 1963 T-Bird..."); cnaReq.setEndDate("7/4/06"); CreateNewAdResponseDocument cnaResDoc = stub.createNewAd(cnaDoc); System.out.println("New ad ID number: "+ cnaResDoc.getCreateNewAdResponse().getNewAdId()); } catch(Exception e){ e.printStackTrace(); } } } |
ClassifiedServicePortTypeStub
類表示實際的服務,您將使用 AXIS_HOME(此處進行了省略,以使用缺省設置)和實際服務的位置對其進行實例化。接下來,通過引用其 Factory
創建請求文檔,并使用其創建新的 CreateNewAdRequest
,而且在此過程中將其添加到請求文檔中。和在服務本身中一樣,可以隨后直接使用 setter 方法設置各個屬性。
為了獲得響應,請使用存根執行 createNewAd()
方法,將其作為參數傳遞給請求文檔。獲得了響應文檔或 CreateNewAtResponseDocument
后,可以使用其提取響應本身以及該響應的屬性。
現在讓我們運行此應用程序。
![]() ![]() |
![]()
|
為了運行客戶機,Francis 首先需要對其進行編譯。執行以下步驟(請參見清單 47)。
清單 47. 編譯客戶機
>>set ANT_HOME=e:\apache-ant-1.6.5 >>PATH=%PATH%;%ANT_HOME%\bin; >>set AXIS2_HOME=e:\axis2 >>cd client >>ant jar.client Buildfile: build.xml init: pre.compile.test: [echo] Stax Availability= true [echo] Axis2 Availability= true compile.src: compile.test: jar.client: BUILD SUCCESSFUL Total time: 2 seconds |
首先,確保環境中包含相應的環境變量。(這假定您已經安裝了所有的 AXIS2_HOME\lib jar 文件。)接下來,轉到 client 目錄(或作為生成過程輸出的任何目錄)并針對 jar.client 目標運行 Ant。應該看到與斜體所示類似的結果(請參見清單 47)。要運行客戶機,首先將 CLASSPATH 修改為包括 resources 目錄以及包含數據綁定過程創建的所有類的目錄(請參見清單 48)。
清單 48. 運行客戶機
>>set CLASSPATH=E:\WSDLFiles\client\resources\;E:\WSDLFiles\client\bui ld\classes\axis2\apache\org\xsd\;%CLASSPATH% >>cd build\classes >>java org.dailymoon.classifieds.Client |
應該看到與清單 49 所示類似的結果:
清單 49. New ad ID number
New ad ID number: 1138 |
本教程的內容到此結束了。
![]() ![]() |
![]()
|