Web Service學習筆記(webservice、soap、wsdl、jws詳細分析)

Web Service概述 

Web Service的定義 
W3C組織對其的定義如下,它是一個軟件系統,爲了支持跨網絡的機器間相互操作交互而設計。Web Service服務通常被定義爲一組模塊化的API,它們可以通過網絡進行調用,來執行遠程系統的請求服務。 

這裏我們從一個程序員的視角來觀察web service。在傳統的程序編碼中,存在這各種的函數方法調用。通常,我們知道一個程序模塊M中的方法A,向其發出調用請求,並傳入A方法需要的參數P,方法A執行完畢後,返回處理結果R。這種函數或方法調用通常發生在同一臺機器上的同一程序語言環境下。現在的我們需要一種能夠在不同計算機間的不同語言編寫的應用程序系統中,通過網絡通訊實現函數和方法調用的能力,而Web service正是應這種需求而誕生的。 

最普遍的一種說法就是,Web Service = SOAP + HTTP + WSDL。其中,SOAP Simple Object Access Protocol)協議是web service的主體,它通過HTTP或者SMTP等應用層協議進行通訊,自身使用XML文件來描述程序的函數方法和參數信息,從而完成不同主機的異構系統間的計算服務處理。這裏的WSDL(Web Services Description Language)web 服務描述語言也是一個XML文檔,它通過HTTP向公衆發佈,公告客戶端程序關於某個具體的 Web service服務的URL信息、方法的命名,參數,返回值等。 
下面,我們先來熟悉一下SOAP協議,看看它是如何描述程序中的函數方法、參數及結果對象的。 

SOAP協議簡介 

什麼是SOAP 
SOAP 指簡單對象訪問協議,它是一種基於XML的消息通訊格式,用於網絡上,不同平臺,不同語言的應用程序間的通訊。可自定義,易於擴展。一條 SOAP 消息就是一個普通的 XML 文檔,包含下列元素: 
• Envelope 元素,標識XML 文檔一條 SOAP 消息 
• Header 元素,包含頭部信息的XML標籤 
• Body 元素,包含所有的調用和響應的主體信息的標籤 
• Fault 元素,錯誤信息標籤。 

以上的元素都在 SOAP的命名空間http://www.w3.org/2001/12/soap-envelope中聲明; 
SOAP的語法規則 
• SOAP 消息必須用 XML 來編碼 
• SOAP 消息必須使用 SOAP Envelope 命名空間 
• SOAP 消息必須使用 SOAP Encoding 命名空間 
• SOAP 消息不能包含 DTD 引用 
• SOAP 消息不能包含 XML 處理指令 

SOAP 消息的基本結構 
Java代碼 
  1. <? xml version="1.0"?>   
  2. <soap:Envelope   
  3. xmlns:soap="http://www.w3.org/2001/12/soap-envelope"  
  4. soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">   
  5. <soap:Header>   
  6.   ...   
  7.   ...   
  8. </soap:Header>   
  9. <soap:Body>   
  10.   ...   
  11.   ...   
  12.   <soap:Fault>   
  13.     ...   
  14.     ...   
  15.   </soap:Fault>   
  16. </soap:Body>   
  17. </soap:Envelope>  

SOAP Envelope 元素 
Envelope 元素是 SOAP 消息的根元素。它指明 XML 文檔是一個SOAP 消息。它的屬性 xmlns:soap的值必須是http://www.w3.org/2001/12/soap-envelope。 
 encodingStyle 屬性,語法:soap:encodingStyle="URI" 
encodingStyle 屬性用於定義文檔中使用的數據類型。此屬性可出現在任何 SOAP 元素中,並會被應用到元素的內容及元素的所有子元素上。 
Java代碼 複製代碼
  1. <? xml version="1.0"?>   
  2. <soap:Envelope   
  3. xmlns:soap="http://www.w3.org/2001/12/soap-envelope"  
  4. soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">   
  5.   ...   
  6.   Message information goes here   
  7.   ...   
  8. </soap:Envelope>  


SOAP Header 元素 

  • actor 屬性,語法soap:actor="URI"

通過沿着消息路徑經過不同的端點,SOAP 消息可從某個發送者傳播到某個接收者。並非 SOAP 消息的所有部分均打算傳送到 SOAP 消息的最終端點,不過,另一個方面,也許打算傳送給消息路徑上的一個或多個端點。SOAP 的 actor 屬性可被用於將 Header 元素尋址到一個特定的端點。 

  • mustUnderstand 屬性 ,語法soap:mustUnderstand="0|1"

SOAP 的 mustUnderstand 屬性可用於標識標題項對於要對其進行處理的接收者來說是強制的還是可選的。假如您向 Header 元素的某個子元素添加了 "mustUnderstand="1",則要求處理此頭部的接收者必須認可此元素。 
[java] view plaincopy
  1. <? xml version="1.0"?>  
  2. <soap:Envelope  
  3. xmlns:soap="http://www.w3.org/2001/12/soap-envelope"  
  4. soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">  
  5. <soap:Header>  
  6. <m:Trans  
  7. xmlns:m="http://www.jsoso.net/transaction/"   
  8. soap:mustUnderstand="1"   
  9. soap:actor="http://www.w3schools.com/appml/ “  >234</m:Trans>  
  10. </soap:Header>  
  11. ...  
  12. ...  
  13. </soap:Envelope>  


SOAP Body 元素 
必需的 SOAP Body 元素可包含打算傳送到消息最終端點的實際 SOAP 消息。Body元素中既可以包含SOAP定義的命名空間中的元素,如Fault,也可以是用戶的應用程序自定義的元素。以下是一個用戶定義的請求: 
[java] view plaincopy
  1. <? xml version="1.0"?>  
  2. <soap:Envelope  
  3. xmlns:soap="http://www.w3.org/2001/12/soap-envelope"  
  4. soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">  
  5. <soap:Body>  
  6.    <m:GetPrice xmlns:m="http://www.jsoso.net/prices">  
  7.       <m:Item>Apples</m:Item>  
  8.    </m:GetPrice>  
  9. </soap:Body>  
  10. </soap:Envelope>  

上面的例子請求蘋果的價格。請注意,上面的 m:GetPrice 和 Item 元素是應用程序專用的元素。它們並不是 SOAP 標準的一部分。而對應的 SOAP 響應應該類似這樣: 
Java代碼 
  1. <?xml version="1.0"?>   
  2. <soap:Envelope   
  3. xmlns:soap="http://www.w3.org/2001/12/soap-envelope"  
  4. soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">   
  5. <soap:Body>   
  6.    <m:GetPriceResponse xmlns:m="http://www.jsoso.net/prices">   
  7.       <m:Price>1.90</m:Price>   
  8.    </m:GetPriceResponse>   
  9. </soap:Body>   
  10. </soap:Envelope>  


SOAP Fault 元素 
Fault 元素表示 SOAP的錯誤消息。它必須是 Body 元素的子元素,且在一條 SOAP 消息中,Fault 元素只能出現一次。Fault 元素擁有下列子元素: 
 
常用的SOAP Fault Codes 
 

HTTP協議中的SOAP 實例 
下面的例子中,一個 GetStockPrice 請求被髮送到了服務器。此請求有一個 StockName 參數,而在響應中則會返回一個 Price 參數。此功能的命名空間被定義在此地址中: "http://www.jsoso.net/stock" 
  • SOAP 請求:(注意HTTP的Head屬性)

Java代碼 
  1. POST /InStock HTTP/1.1  
  2. Host: www.jsoso.net   
  3. Content-Type: application/soap+xml; charset=utf-8  
  4. Content-Length: XXX   
  5.   
  6. <? xml version="1.0"?>   
  7. <soap:Envelope   
  8. xmlns:soap="http://www.w3.org/2001/12/soap-envelope"  
  9. soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">   
  10.   <soap:Body xmlns:m="http://www.jsoso.net/stock">   
  11.     <m:GetStockPrice>   
  12.       <m:StockName>IBM</m:StockName>   
  13.     </m:GetStockPrice>   
  14.   </soap:Body>     
  15. </soap:Envelope>  


  • SOAP 響應:(注意HTTP的Head屬性)

Java代碼 
  1. HTTP/1.1 200 OK   
  2. Content-Type: application/soap+xml; charset=utf-8  
  3. Content-Length: XXX   
  4.   
  5. <? xml version="1.0"?>   
  6. <soap:Envelope   
  7. xmlns:soap="http://www.w3.org/2001/12/soap-envelope"  
  8. soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">   
  9.   <soap:Body xmlns:m="http://www.jsoso.net/stock">   
  10.     <m:GetStockPriceResponse>   
  11.       <m:Price>34.5</m:Price>   
  12.     </m:GetStockPriceResponse>   
  13.   </soap:Body>     
  14. </soap:Envelope>  


HTTP協議中的SOAP RPC工作流程 
 

WSDL簡介 
介紹過了SOAP,讓我們關注Web Service中另外一個重要的組成WSDL。 
WSDL的主要文檔元素 
 
WSDL文檔可以分爲兩部分。頂部分由抽象定義組成,而底部分則由具體描述組成。抽象部分以獨立於平臺和語言的方式定義SOAP消息,它們並不包含任何隨機器或語言而變的元素。這就定義了一系列服務,截然不同的應用都可以實現。具體部分,如數據的序列化則歸入底部分,因爲它包含具體的定義。在上述的文檔元素中,<types>、<message>、<portType>屬於抽象定義層,<binding>、<service>屬於具體定義層。所有的抽象可以是單獨存在於別的文件中,也可以從主文檔中導入。 

WSDL文檔的結構實例解析 
下面我們將通過一個實際的WSDL文檔例子來詳細說明各標籤的作用及關係。 
Java代碼 
  1. <?xml version="1.0" encoding="UTF-8"?>   
  2. <definitions   
  3.  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"  
  4.  xmlns:tns="http://www.jsoso.com/wstest"  
  5.  xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
  6.  xmlns="http://schemas.xmlsoap.org/wsdl/"  
  7.  targetNamespace="http://www.jsoso.com/wstest"  
  8.  name="Example">   
  9.   
  10. <types>   
  11.   <xsd:schema>   
  12.   <xsd:import  
  13.    namespace="http://www.jsoso.com/wstest"  
  14.    schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import>   
  15.   </xsd:schema>   
  16. </types>   
  17.   
  18. <message name="toSayHello">   
  19.   <part name="userName" type="xsd:string"></part>   
  20. </message>   
  21. <message name="toSayHelloResponse">   
  22.   <part name="returnWord" type="xsd:string"></part>   
  23. </message>   
  24.   
  25. <message name="sayHello">   
  26.   <part name="person" type="tns:person"></part>   
  27.   <part name="arg1" type="xsd:string"></part>   
  28. </message>   
  29. <message name="sayHelloResponse">   
  30.   <part name="personList" type="tns:personArray"></part>   
  31. </message>   
  32. <message name="HelloException">   
  33.   <part name="fault" element="tns:HelloException"></part>   
  34. </message>   
  35.   
  36. <portType name="Example">   
  37.   <operation name="toSayHello" parameterOrder="userName">   
  38.     <input message="tns:toSayHello"></input>   
  39.     <output message="tns:toSayHelloResponse"></output>   
  40.   </operation>   
  41.   <operation name="sayHello" parameterOrder="person arg1">   
  42.     <input message="tns:sayHello"></input>   
  43.     <output message="tns:sayHelloResponse"></output>   
  44.     <fault message="tns:HelloException" name="HelloException"></fault>   
  45.   </operation>   
  46. </portType>   
  47.   
  48. <binding name="ExamplePortBinding" type="tns:Example">   
  49.   <soap:binding   
  50.     transport="http://schemas.xmlsoap.org/soap/http"    
  51.     style="rpc"></soap:binding>   
  52.   <operation name="toSayHello">   
  53.     <soap:operation soapAction="sayHello"></soap:operation>   
  54.     <input>   
  55.       <soap:body use="literal"  
  56.         namespace="http://www.jsoso.com/wstest"></soap:body>   
  57.     </input>   
  58.     <output>   
  59.       <soap:body use="literal"  
  60.          namespace="http://www.jsoso.com/wstest"></soap:body>   
  61.     </output>   
  62.   </operation>   
  63.   <operation name="sayHello">   
  64.     <soap:operation soapAction="sayHello"></soap:operation>   
  65.     <input>   
  66.       <soap:body use="literal"  
  67.         namespace="http://www.jsoso.com/wstest"></soap:body>   
  68.     </input>   
  69.     <output>   
  70.       <soap:body use="literal"  
  71.         namespace="http://www.jsoso.com/wstest"></soap:body>   
  72.     </output>   
  73.     <fault name="HelloException">   
  74.       <soap:fault name="HelloException" use="literal"></soap:fault>   
  75.     </fault>   
  76.     </operation>   
  77. </binding>   
  78.   
  79. <service name="Example">   
  80.   <port name="ExamplePort" binding="tns:ExamplePortBinding">   
  81.     <soap:address location="http://localhost:8080/hello"></soap:address>   
  82.   </port>   
  83. </service>   
  84. </definitions>   

由於上面的事例XML較長,我們將其逐段分解講解 

WSDL文檔的根元素:<definitions> 
Java代碼 
  1. <definitions   
  2.  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"  
  3.  xmlns:tns="http://www.jsoso.com/wstest"  
  4.  xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
  5.  xmlns="http://schemas.xmlsoap.org/wsdl/"  
  6.  targetNamespace="http://www.jsoso.com/wstest"  
  7.  name="Example">   
  8. ……   
  9. ……   
  10. </definitions>   

<definitions>定義了文檔中用到的各個xml元素的namespace縮寫,也界定了本文檔自己的targetNamespace="http://www.jsoso.com/wstest",這意味着其它的XML要引用當前XML中的元素時,要聲明這個namespace。注意xmlns:tns="http://www.jsoso.com/wstest"這個聲明,它標示了使用tns這個前綴指向自身的命名空間。 

引用
WSDL文檔數據類型定義元素:<types>

Java代碼 
  1. <types>   
  2.   <xsd:schema>   
  3.   <xsd:import  
  4.    namespace="http://www.jsoso.com/wstest"  
  5.    schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import>   
  6.   </xsd:schema>   
  7. </types>  

<types>標籤定義了當前的WSDL文檔用到的數據類型。要說明的是,爲了最大程度的平臺中立性,WSDL 使用 XML Schema 語法來定義數據類型。這些數據類型用來定義web service方法的參數和返回指。對於通用的原生數據類型如:integer , boolean , char , float等,在W3C的標準文檔http://www.w3.org/2001/XMLSchema中已經做了定義。這裏我們要引入的schema定義schemaLocation="http://localhost:8080/hello?xsd=1"是我們自定義的Java對象類型。 

WSDL文檔消息體定義元素:< message > 
Java代碼 
  1. <message name="toSayHello">   
  2.   <part name="userName" type="xsd:string"></part>   
  3. </message>   
  4. <message name="toSayHelloResponse">   
  5.   <part name="returnWord" type="xsd:string"></part>   
  6. </message>   
  7.   
  8. <message name="sayHello">   
  9.   <part name="person" type="tns:person"></part>   
  10.   <part name="arg1" type="xsd:string"></part>   
  11. </message>   
  12. <message name="sayHelloResponse">   
  13.   <part name="personList" type="tns:personArray"></part>   
  14. </message>   
  15. <message name="HelloException">   
  16.   <part name="fault" element="tns:HelloException"></part>   
  17. </message>  

<message>元素定義了web service函數的參數。<message>元素中的每個<part>子元素都和某個參數相符。輸入參數在<message>元素中定義,與輸出參數相隔離,輸出參數有自己的<message>元素。兼作輸入、輸出的參數在輸入輸出的<message>元素中有它們相應的<part>元素。輸出<message>元素以"Response"結尾,對Java而言方法得返回值就對應一個輸出的<message>。每個<part>元素都有名字和類型屬性,就像函數的參數有參數名和參數類型。 

在上面的文檔中有兩個輸入參數、兩個輸出參數和一個錯誤參數(對應Java中的Exception)。 

 輸入參數<message>的name屬性分別命名爲toSayHello,sayHello。 
toSayHello對應輸入參數userName,參數類型爲xsd:string,在Java語言中就是String; 
sayHello對應兩個輸入參數person和arg1,類型爲tns:person和xsd:string。這裏tns:person類型就是引用了< types >標籤中的類型定義。 

 輸出參數<message>的name屬性分別命名爲toSayHelloResponse和sayHelloResponse。 
這個名稱和輸入參數的<message>標籤name屬性對應,在其後面加上Response尾綴。 
toSayHelloResponse對應的返回值是returnWord,參數類型爲xsd:string; 
sayHelloResponse對應的返回值是personList,參數類型爲tns:personArray(自定義類型); 

 錯誤參數<message>的name屬性爲HelloException。 
它的<part>子標籤element而不是type來定義類型。 

以上的message標籤的name屬性通常使用web service函數方法名作爲參照,錯誤參數標籤則使用異常類名爲參照。標籤中的參數名稱,即part子元素的name屬性是可自定義的(下一章節詳細說明)。message標籤的參數類型將引用types標籤的定義。 

WSDL文檔函數體定義元素:< portType > 
[java] view plaincopy
  1. <portType name="Example">  
  2.   <operation name="toSayHello" parameterOrder="userName">  
  3.     <input message="tns:toSayHello"></input>  
  4.     <output message="tns:toSayHelloResponse"></output>  
  5.   </operation>  
  6.   <operation name="sayHello" parameterOrder="person arg1">  
  7.     <input message="tns:sayHello"></input>  
  8.     <output message="tns:sayHelloResponse"></output>  
  9.     <fault message="tns:HelloException" name="HelloException"></fault>  
  10.   </operation>  
  11. </portType>  

<portType> 元素是最重要的 WSDL 元素。它可描述一個 web service、可被執行的操作,以及相關的消息。portType的name屬性對應Java中的一個服務類的類名。<portType> 元素使用其子元素< operation>描述一個web service的服務方法。 

在<operation>元素中,name屬性表示服務方法名,parameterOrder屬性表示方法的參數順序,使用空格符分割多個參數,如:“parameterOrder="person arg1”。<operation>元素的子標籤<input>表示輸入參數說明,它引用<message>標籤中的輸入參數。<output>表示輸出參數說明,它引用<message>標籤中的輸出參數。<fault>標籤在Java方法中的特別用來表示異常(其它語言有對應的錯誤處理機制),它引用<message>標籤中的錯誤參數。 

WSDL綁定實現定義元素:< binding > 
[java] view plaincopy
  1. <binding name="ExamplePortBinding" type="tns:Example">  
  2.   <soap:binding  
  3.     transport="http://schemas.xmlsoap.org/soap/http"   
  4.     style="rpc"></soap:binding>  
  5.   <operation name="toSayHello">  
  6.     <soap:operation soapAction="sayHello"></soap:operation>  
  7.     <input>  
  8.       <soap:body use="literal"  
  9.         namespace="http://www.jsoso.com/wstest"></soap:body>  
  10.     </input>  
  11.     <output>  
  12.       <soap:body use="literal"  
  13.          namespace="http://www.jsoso.com/wstest"></soap:body>  
  14.     </output>  
  15.   </operation>  
  16.   <operation name="sayHello">  
  17.     <soap:operation soapAction="sayHello"></soap:operation>  
  18.     <input>  
  19.       <soap:body use="literal"  
  20.         namespace="http://www.jsoso.com/wstest"></soap:body>  
  21.     </input>  
  22.     <output>  
  23.       <soap:body use="literal"  
  24.         namespace="http://www.jsoso.com/wstest"></soap:body>  
  25.     </output>  
  26.     <fault name="HelloException">  
  27.       <soap:fault name="HelloException" use="literal"></soap:fault>  
  28.     </fault>  
  29.     </operation>  
  30. </binding>  

<binding>標籤是完整描述協議、序列化和編碼的地方,<types>,<message>和<portType>標籤處理抽象的數據內容,而<binding>標籤是處理數據傳輸的物理實現。 
<binding>標籤把前三部分的抽象定義具體化。 

首先<binding>標籤使用<soap:binding>的transport和style屬性定義了Web Service的通訊協議HTTP和SOAP的請求風格RPC。其次<operation>子標籤將portType中定義的operation同SOAP的請求綁定,定義了操作名稱soapAction,輸出輸入參數和異常的編碼方式及命名空間。 

WSDL服務地址綁定元素:< service >  
[java] view plaincopy
  1. <service name="Example">  
  2.   <port name="ExamplePort" binding="tns:ExamplePortBinding">  
  3.     <soap:address location="http://localhost:8080/hello"></soap:address>  
  4.   </port>  
  5. </service>  

service是一套<port>元素。在一一對應形式下,每個<port>元素都和一個location關聯。如果同一個<binding>有多個<port>元素與之關聯,可以使用額外的URL地址作爲替換。 

一個WSDL文檔中可以有多個<service>元素,而且多個<service>元素十分有用,其中之一就是可以根據目標URL來組織端口。在一個WSDL文檔中,<service>的name屬性用來區分不同的service。在同一個service中,不同端口,使用端口的"name"屬性區分。 

這一章節,我們簡單的描述了WSDL對SOAP協議的支持,以及在Web Service中的作用。在接下來的章節中,我們將學習如何使用Java6.0的Annotation標籤來定義和生成對應的WSDL。 

JavaSE6.0下的Web Service 
從JavaSE6.0開始,Java引入了對Web Service的原生支持。我們只需要簡單的使用Java的Annotation標籤即可將標準的Java方法發佈成Web Service。(PS:Java Annotation資料請參考 JDK5.0 Annotation學習筆記(一) ) 

但不是所有的Java類都可以發佈成Web Service。Java類若要成爲一個實現了Web Service的bean,它需要遵循下邊這些原則: 
  •  這個類必須是public類
  •  這些類不能是final的或者abstract
  •  這個類必須有一個公共的默認構造函數
  •  這個類絕對不能有finalize()方法

下面我們將通過一個具體的Java Web Service代碼例子,配合上述的WSDL文件,講述如何編寫JavaSE6.0的原生Web Service應用。 

完整的Java Web Service類代碼 

[java] view plaincopy
  1. package org.jsoso.jws.server;  
  2.   
  3. import java.util.ArrayList;  
  4. import javax.jws.WebMethod;  
  5. import javax.jws.WebParam;  
  6. import javax.jws.WebResult;  
  7. import javax.jws.WebService;  
  8. import javax.jws.WebParam.Mode;  
  9. import javax.jws.soap.SOAPBinding;  
  10. /  
  11.  * 提供WebService服務的類  
  12.  */  
  13. @WebService(name="Example", targetNamespace="http://www.jsoso.com/wstest", serviceName="Example")  
  14. @SOAPBinding(style=SOAPBinding.Style.RPC)  
  15. public class Example {  
  16.     private ArrayList<Person> persons = new ArrayList<Person>();;  
  17.     /** 
  18.      *  
  19.      * 返回一個字符串 
  20.      * @param userName 
  21.      * @return 
  22.      */  
  23.     @WebMethod(operationName="toSayHello",action="sayHello",exclude=false)  
  24.     @WebResult(name="returnWord")//自定義該方法返回值在WSDL中相關的描述  
  25.     public String sayHello(@WebParam(name="userName")String userName) {  
  26.         return "Hello:" + userName;  
  27.     }  
  28.   
  29.     /** 
  30.      * web services 方法的返回值與參數的類型不能爲接口 
  31.      * @param person 
  32.      * @return 
  33.      * @throws HelloException 
  34.      */  
  35.     @WebMethod(operationName="sayHello", action="sayHello")  
  36.     @WebResult(partName="personList")  
  37.     public Person[] sayHello(@WebParam(partName="person", mode=Mode.IN)Person person,   
  38.             String userName) throws HelloException {  
  39.         if (person == null || person.getName() == null) {  
  40.             throw new HelloException("說hello出錯,對像爲空。。");  
  41.         }  
  42.         System.out.println(person.getName() + " 對 " + userName + " 說:Hello,我今年" + person.getAge() + "歲");  
  43.         persons.add(person);  
  44.         return persons.toArray(new Person[0]);  
  45.     }  
  46. }  


Annotation 1@WebService(name="Example", targetNamespace="http://www.jsoso.com/wstest", serviceName="Example") 
@WebService標籤主要將類暴露爲WebService,其中targetNamespace屬性定義了自己的命名空間,serviceName則定義了< definitions >標籤和<service>標籤的name屬性。 

Annotation 2:@SOAPBinding(style=SOAPBinding.Style.RPC) 
@SOAPBinding標籤定義了WSDL文檔中SOAP的消息協議,其中style屬性對應SOAP的文檔類型,可選的有RPC和DOCUMENT 

Annotation 3:@WebMethod(operationName="toSayHello",action="sayHello",exclude=false) 
@WebMethod定義Web Service運作的方法, 
屬性action 對應操作的活動 ,如<soap:operation soapAction="sayHello" /> 
屬性operationName匹配的wsdl:operation 的名稱,如<operation name="toSayHello" parameterOrder="userName"> 
屬性exclude 用於阻止將某一繼承方法公開爲web服務,默認爲false 

Annotation 4:@WebResult(name="returnWord") 
@ WebResult定義方法返回值得名稱,如<part name="returnWord" type="xsd:string" /> 

Annotation 5:@WebParam(partName="person", mode=Mode.IN 
@WebParam定義方法的參數名稱,如<part name="person" type="tns:person" />,其中mode屬性表示參數的流向,可選值有IN / OUT / INOUT 

這裏要着重說明的是,上述Web Service類的sayHello方法中,帶有HelloException這個異常聲明,造成該服務類不能直接發佈成Web Service。需要使用wsgen工具爲其生存異常Bean。關於wsgen工具的使用,請參考wsgen與wsimport命令說明 

發佈一個的Java Web Service 
在完成了上述的Web Service Annotation註釋後,我們使用wsgen工具爲其進行服務資源文件的構造(這裏主要是生成一個名爲org.jsoso.jws.server.jaxws.HelloExceptionBean的異常bean類),最後使用以下的類發佈Web 服務: 
[java] view plaincopy
  1. package org.jsoso.jws.server;  
  2.   
  3. import java.util.LinkedList;  
  4. import java.util.List;  
  5. import javax.xml.ws.Binding;  
  6. import javax.xml.ws.Endpoint;  
  7. import javax.xml.ws.handler.Handler;  
  8.   
  9. /** 
  10.  * @author zsy 啓動web services服務 
  11.  */  
  12. public class StartServer {  
  13.   
  14.     /** 
  15.      * @param args 
  16.      */  
  17.     public static void main(String[] args) {  
  18.         /* 
  19.          * 生成Example 服務實例 
  20.          */  
  21.         Example serverBean = new Example();  
  22.         /* 
  23.          * 發佈Web Service到http://localhost:8080/hello地址 
  24.          */  
  25.         Endpoint endpoint =   
  26.            Endpoint.publish("http://localhost:8080/hello", serverBean);  
  27.         Binding binding = endpoint.getBinding();  
  28.         /* 
  29.          * 設置一個SOAP協議處理棧 
  30.          * 這裏就簡單得打印SOAP的消息文本 
  31.          */  
  32.         List<Handler> handlerChain = new LinkedList<Handler>();  
  33.         handlerChain.add(new TraceHandler());  
  34.         binding.setHandlerChain(handlerChain);  
  35.         System.out.println("服務已啓動 http://localhost:8080/hello");  
  36.     }  
  37. }  

在控制檯運行這個類,就可以使用URL :http://localhost:8080/hello?wsdl 瀏覽到上文所描述的WSDL的全文了。這說明您的第一個Web Service應用發佈成功! 

構建Web Service客戶端 
使用JavaSE6.0構建Web Service的客戶端是一件相當簡單的事。這裏我們要使用到JDK中的另一個命令行工具wsimport。在控制檯下輸入以下命令: 
引用
wsimport -d ./bin -s ./src -p org.jsoso.jws.client.ref http://localhost:8080/hello?wsdl

即可在包org.jsoso.jws.client.ref中生成客戶端的存根及框架文件。其中我們要使用的類只有兩個:服務類Example_Service和本地接口Example。編寫如下客戶端,即可調用Web Service服務: 
[java] view plaincopy
  1. package org.jsoso.jws.client;  
  2.   
  3. import org.jsoso.jws.client.ref.*;  
  4.   
  5. public class RunClient {  
  6.   
  7.     /** 
  8.      * @param args 
  9.      */  
  10.     public static void main(String[] args) {  
  11.         //初始化服務框架類  
  12.         Example_Service service = new Example_Service();  
  13.         //或者本地服務藉口的實例  
  14.         Example server = (Example) service.getExamplePort();  
  15.         try {  
  16.             //調用web service的toSayHello方法  
  17.             System.out.println("輸入toSayHello的返回值——" + server.toSayHello("阿土"));           
  18.              Person person = new Person();  
  19.              person.setName("阿土");  
  20.              person.setAge(25);  
  21.              //調用web service的sayHello方法  
  22.              server.sayHello(person, "機器人");  
  23.                
  24.              person = new Person();  
  25.              person.setName("aten");  
  26.              person.setAge(30);  
  27.              //調用web service的sayHello方法  
  28.              PersonArray list = server.sayHello(person, "機器人");  
  29.             //輸出返回值  
  30.              System.out.println("/n以下輸入sayHello的返回值——");  
  31.             for (Person p : list.getItem()) {  
  32.                 System.out.println(p.getName() + ":" + p.getAge());  
  33.             }             
  34.         } catch (HelloException_Exception e) {  
  35.             e.printStackTrace();  
  36.         }  
  37.     }  
  38. }  

屆此,本次Web Service的學習暫告一個段落。Java Web Service是一個相當龐大的知識體系,其中涉及的相關技術較多,這裏無法一一道來,我們將會在今後的開發和使用中,同大家做進一步深入的探討和學習。 

附錄:wsgen與wsimport命令說明 

wsgen 
wsgen是在JDK的bin目錄下的一個exe文件(Windows版),該命令的主要功能是用來生成合適的JAX-WS。它讀取Web Service的終端類文件,同時生成所有用於發佈Web Service所依賴的源代碼文件和經過編譯過的二進制類文件。這裏要特別說明的是,通常在Web Service Bean中用到的異常類會另外生成一個描述Bean,如果Web Service Bean中的方法有申明拋出異常,這一步是必需的,否則服務器無法綁定該對像。此外,wsgen還能輔助生成WSDL和相關的xsd文件。wsgen從資源文件生成一個完整的操作列表並驗證web service是否合法,可以完整發布。 
命令參數說明: 
  •  -cp 定義classpath
  •  -r 生成 bean的wsdl文件的存放目錄
  •  -s 生成發佈Web Service的源代碼文件的存放目錄(如果方法有拋出異常,則會生成該異常的描述類源文件)
  •  -d 生成發佈Web Service的編譯過的二進制類文件的存放目錄(該異常的描述類的class文件)

命令範例:wsgen -cp ./bin -r ./wsdl -s ./src -d ./bin -wsdl org.jsoso.jws.server.Example 

wsimport 
wsimport也是在JDK的bin目錄下的一個exe文件(Windows版),主要功能是根據服務端發佈的wsdl文件生成客戶端存根及框架,負責與Web Service 服務器通信,並在將其封裝成實例,客戶端可以直接使用,就像使用本地實例一樣。對Java而言,wsimport幫助程序員生存調用web service所需要的客戶端類文件.java和.class。要提醒指出的是,wsimport可以用於非Java的服務器端,如:服務器端也許是C#編寫的web service,通過wsimport則生成Java的客戶端實現。 
命令參數說明: 
  •  -d 生成客戶端執行類的class文件的存放目錄
  •  -s 生成客戶端執行類的源文件的存放目錄
  •  -p 定義生成類的包名

命令範例:wsimport -d ./bin -s ./src -p org.jsoso.jws.client.ref http://localhost:8080/hello?wsdl 
發佈了46 篇原創文章 · 獲贊 31 · 訪問量 42萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章