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向公衆公佈,公告client程序關於某個詳細的 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 消息的基本結構
- <? xml version="1.0"?>
- <soap:Envelope
- xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
- soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
- <soap:Header>
- ...
- ...
- </soap:Header>
- <soap:Body>
- ...
- ...
- <soap:Fault>
- ...
- ...
- </soap:Fault>
- </soap:Body>
- </soap:Envelope>
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Header>
...
...
</soap:Header>
<soap:Body>
...
...
<soap:Fault>
...
...
</soap:Fault>
</soap:Body>
</soap:Envelope>
SOAP Envelope 元素
Envelope 元素是 SOAP 消息的根元素。它指明 XML 文檔是一個SOAP 消息。它的屬性 xmlns:soap的值必須是http://www.w3.org/2001/12/soap-envelope。
encodingStyle 屬性,語法:soap:encodingStyle="URI"
encodingStyle 屬性用於定義文檔中使用的數據類型。此屬性可出現在不論什麼 SOAP 元素中,並會被應用到元素的內容及元素的所有子元素上。
- <? xml version="1.0"?>
- <soap:Envelope
- xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
- soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
- ...
- Message information goes here
- ...
- </soap:Envelope>
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
...
Message information goes here
...
</soap:Envelope>
SOAP Header 元素
- actor 屬性,語法soap:actor="URI"
經過沿着消息路徑通過不一樣的端點,SOAP 消息可從某個發送者傳播到某個接收者。並非 SOAP 消息的所有部分均打算傳送到 SOAP 消息的終於端點,只是,還有一個方面,或許打算傳送給消息路徑上的一個或多個端點。SOAP 的 actor 屬性可被用於將 Header 元素尋址到一個特定的端點。
- mustUnderstand 屬性 ,語法soap:mustUnderstand="0|1"
SOAP 的 mustUnderstand 屬性可用於標識標題項對於要對其進行處理的接收者來講是強制的仍是可選的。假如您向 Header 元素的某個子元素加入�了 "mustUnderstand="1",則要求處理此頭部的接收者必須承認此元素。
- <? xml version="1.0"?>
- <soap:Envelope
- xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
- soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
- <soap:Header>
- <m:Trans
- xmlns:m="http://www.jsoso.net/transaction/"
- soap:mustUnderstand="1"
- soap:actor="http:
- </soap:Header>
- ...
- ...
- </soap:Envelope>
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Header>
<m:Trans
xmlns:m="http://www.jsoso.net/transaction/"
soap:mustUnderstand="1"
soap:actor="http://www.w3schools.com/appml/ 「 >234</m:Trans>
</soap:Header>
...
...
</soap:Envelope>
SOAP Body 元素
必需的 SOAP Body 元素可包括打算傳送到消息終於端點的實際 SOAP 消息。Body元素中既可以包括SOAP定義的命名空間中的元素,如Fault,也可以是用戶的應用程序本身定義的元素。下面是一個用戶定義的請求:
- <? xml version="1.0"?>
- <soap:Envelope
- xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
- soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
- <soap:Body>
- <m:GetPrice xmlns:m="http://www.jsoso.net/prices">
- <m:Item>Apples</m:Item>
- </m:GetPrice>
- </soap:Body>
- </soap:Envelope>
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body>
<m:GetPrice xmlns:m="http://www.jsoso.net/prices">
<m:Item>Apples</m:Item>
</m:GetPrice>
</soap:Body>
</soap:Envelope>
上面的樣例請求蘋果的價格。請注意,上面的 m:GetPrice 和 Item 元素是應用程序專用的元素。它們並不是 SOAP 標準的一部分。而相應的 SOAP 響應應該類似這樣:
- <?xml version="1.0"?>
- <soap:Envelope
- xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
- soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
- <soap:Body>
- <m:GetPriceResponse xmlns:m="http://www.jsoso.net/prices">
- <m:Price>1.90</m:Price>
- </m:GetPriceResponse>
- </soap:Body>
- </soap:Envelope>
<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body>
<m:GetPriceResponse xmlns:m="http://www.jsoso.net/prices">
<m:Price>1.90</m:Price>
</m:GetPriceResponse>
</soap:Body>
</soap:Envelope>
SOAP Fault 元素
Fault 元素表示 SOAP的錯誤消息。它必須是 Body 元素的子元素,且在一條 SOAP 消息中,Fault 元素僅僅能出現一次。Fault 元素擁有下列子元素:
常用的SOAP Fault Codes
HTTP協議中的SOAP 實例
如下的樣例中,一個 GetStockPrice 請求被髮送到了server。此請求有一個 StockName 參數,而在響應中則會返回一個 Price 參數。此功能的命名空間被定義在此地址中: "http://www.jsoso.net/stock"
- POST /InStock HTTP/1.1
- Host: www.jsoso.net
- Content-Type: application/soap+xml; charset=utf-8
- Content-Length: XXX
-
- <? xml version="1.0"?>
- <soap:Envelope
- xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
- soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
- <soap:Body xmlns:m="http://www.jsoso.net/stock">
- <m:GetStockPrice>
- <m:StockName>IBM</m:StockName>
- </m:GetStockPrice>
- </soap:Body>
- </soap:Envelope>
POST /InStock HTTP/1.1
Host: www.jsoso.net
Content-Type: application/soap+xml; charset=utf-8
Content-Length: XXX
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body xmlns:m="http://www.jsoso.net/stock">
<m:GetStockPrice>
<m:StockName>IBM</m:StockName>
</m:GetStockPrice>
</soap:Body>
</soap:Envelope>
- HTTP/1.1 200 OK
- Content-Type: application/soap+xml; charset=utf-8
- Content-Length: XXX
-
- <? xml version="1.0"?>
- <soap:Envelope
- xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
- soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
- <soap:Body xmlns:m="http://www.jsoso.net/stock">
- <m:GetStockPriceResponse>
- <m:Price>34.5</m:Price>
- </m:GetStockPriceResponse>
- </soap:Body>
- </soap:Envelope>
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: XXX
<? xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body xmlns:m="http://www.jsoso.net/stock">
<m:GetStockPriceResponse>
<m:Price>34.5</m:Price>
</m:GetStockPriceResponse>
</soap:Body>
</soap:Envelope>
HTTP協議中的SOAP RPC工做流程
WSDL簡單介紹
介紹過了SOAP,讓咱們關注Web Service中另一個重要的組成WSDL。
WSDL的主要文檔元素
WSDL文檔可以分爲兩部分。頂部分由抽象定義組成,而底部分則由詳細描寫敘述組成。抽象部分以獨立於平臺和語言的方式定義SOAP消息,它們並不包括不論什麼隨機器或語言而變的元素。這就定義了一系列服務,大相徑庭的應用都可以實現。詳細部分,如數據的序列化則納入底部分,因爲它包括詳細的定義。在上述的文檔元素中,<types>、<message>、<portType>屬於抽象定義層,<binding>、<service>屬於詳細定義層。所有的抽象可以是單獨存在於別的文件裏,也可以從主文檔中導入。
WSDL文檔的結構實例解析
如下咱們將經過一個實際的WSDL文檔樣例來詳細說明各標籤的做用及關係。
- <?xml version="1.0" encoding="UTF-8"?>
- <definitions
- xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
- xmlns:tns="http://www.jsoso.com/wstest"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns="http://schemas.xmlsoap.org/wsdl/"
- targetNamespace="http://www.jsoso.com/wstest"
- name="Example">
-
- <types>
- <xsd:schema>
- <xsd:import
- namespace="http://www.jsoso.com/wstest"
- schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import>
- </xsd:schema>
- </types>
-
- <message name="toSayHello">
- <part name="userName" type="xsd:string"></part>
- </message>
- <message name="toSayHelloResponse">
- <part name="returnWord" type="xsd:string"></part>
- </message>
-
- <message name="sayHello">
- <part name="person" type="tns:person"></part>
- <part name="arg1" type="xsd:string"></part>
- </message>
- <message name="sayHelloResponse">
- <part name="personList" type="tns:personArray"></part>
- </message>
- <message name="HelloException">
- <part name="fault" element="tns:HelloException"></part>
- </message>
-
- <portType name="Example">
- <operation name="toSayHello" parameterOrder="userName">
- <input message="tns:toSayHello"></input>
- <output message="tns:toSayHelloResponse"></output>
- </operation>
- <operation name="sayHello" parameterOrder="person arg1">
- <input message="tns:sayHello"></input>
- <output message="tns:sayHelloResponse"></output>
- <fault message="tns:HelloException" name="HelloException"></fault>
- </operation>
- </portType>
-
- <binding name="ExamplePortBinding" type="tns:Example">
- <soap:binding
- transport="http://schemas.xmlsoap.org/soap/http"
- style="rpc"></soap:binding>
- <operation name="toSayHello">
- <soap:operation soapAction="sayHello"></soap:operation>
- <input>
- <soap:body use="literal"
- namespace="http://www.jsoso.com/wstest"></soap:body>
- </input>
- <output>
- <soap:body use="literal"
- namespace="http://www.jsoso.com/wstest"></soap:body>
- </output>
- </operation>
- <operation name="sayHello">
- <soap:operation soapAction="sayHello"></soap:operation>
- <input>
- <soap:body use="literal"
- namespace="http://www.jsoso.com/wstest"></soap:body>
- </input>
- <output>
- <soap:body use="literal"
- namespace="http://www.jsoso.com/wstest"></soap:body>
- </output>
- <fault name="HelloException">
- <soap:fault name="HelloException" use="literal"></soap:fault>
- </fault>
- </operation>
- </binding>
-
- <service name="Example">
- <port name="ExamplePort" binding="tns:ExamplePortBinding">
- <soap:address location="http://localhost:8080/hello"></soap:address>
- </port>
- </service>
- </definitions>
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.jsoso.com/wstest"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://www.jsoso.com/wstest"
name="Example">
<types>
<xsd:schema>
<xsd:import
namespace="http://www.jsoso.com/wstest"
schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import>
</xsd:schema>
</types>
<message name="toSayHello">
<part name="userName" type="xsd:string"></part>
</message>
<message name="toSayHelloResponse">
<part name="returnWord" type="xsd:string"></part>
</message>
<message name="sayHello">
<part name="person" type="tns:person"></part>
<part name="arg1" type="xsd:string"></part>
</message>
<message name="sayHelloResponse">
<part name="personList" type="tns:personArray"></part>
</message>
<message name="HelloException">
<part name="fault" element="tns:HelloException"></part>
</message>
<portType name="Example">
<operation name="toSayHello" parameterOrder="userName">
<input message="tns:toSayHello"></input>
<output message="tns:toSayHelloResponse"></output>
</operation>
<operation name="sayHello" parameterOrder="person arg1">
<input message="tns:sayHello"></input>
<output message="tns:sayHelloResponse"></output>
<fault message="tns:HelloException" name="HelloException"></fault>
</operation>
</portType>
<binding name="ExamplePortBinding" type="tns:Example">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="rpc"></soap:binding>
<operation name="toSayHello">
<soap:operation soapAction="sayHello"></soap:operation>
<input>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</input>
<output>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</output>
</operation>
<operation name="sayHello">
<soap:operation soapAction="sayHello"></soap:operation>
<input>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</input>
<output>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</output>
<fault name="HelloException">
<soap:fault name="HelloException" use="literal"></soap:fault>
</fault>
</operation>
</binding>
<service name="Example">
<port name="ExamplePort" binding="tns:ExamplePortBinding">
<soap:address location="http://localhost:8080/hello"></soap:address>
</port>
</service>
</definitions>
由於上面的事例XML較長,咱們將其逐段分解解說
WSDL文檔的根元素:<definitions>
- <definitions
- xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
- xmlns:tns="http://www.jsoso.com/wstest"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns="http://schemas.xmlsoap.org/wsdl/"
- targetNamespace="http://www.jsoso.com/wstest"
- name="Example">
- ……
- ……
- </definitions>
<definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.jsoso.com/wstest"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://www.jsoso.com/wstest"
name="Example">
……
……
</definitions>
<definitions>定義了文檔中用到的各個xml元素的namespace縮寫,也界定了本文檔本身的targetNamespace="http://www.jsoso.com/wstest",這意味着其餘的XML要引用當前XML中的元素時,要聲明這個namespace。注意xmlns:tns="http://www.jsoso.com/wstest"這個聲明,它標示了使用tns這個前綴指向自身的命名空間。
引用
WSDL文檔數據類型定義元素:<types>
- <types>
- <xsd:schema>
- <xsd:import
- namespace="http://www.jsoso.com/wstest"
- schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import>
- </xsd:schema>
- </types>
<types>
<xsd:schema>
<xsd:import
namespace="http://www.jsoso.com/wstest"
schemaLocation="http://localhost:8080/hello?xsd=1"></xsd:import>
</xsd:schema>
</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 >
- <message name="toSayHello">
- <part name="userName" type="xsd:string"></part>
- </message>
- <message name="toSayHelloResponse">
- <part name="returnWord" type="xsd:string"></part>
- </message>
-
- <message name="sayHello">
- <part name="person" type="tns:person"></part>
- <part name="arg1" type="xsd:string"></part>
- </message>
- <message name="sayHelloResponse">
- <part name="personList" type="tns:personArray"></part>
- </message>
- <message name="HelloException">
- <part name="fault" element="tns:HelloException"></part>
- </message>
<message name="toSayHello">
<part name="userName" type="xsd:string"></part>
</message>
<message name="toSayHelloResponse">
<part name="returnWord" type="xsd:string"></part>
</message>
<message name="sayHello">
<part name="person" type="tns:person"></part>
<part name="arg1" type="xsd:string"></part>
</message>
<message name="sayHelloResponse">
<part name="personList" type="tns:personArray"></part>
</message>
<message name="HelloException">
<part name="fault" element="tns:HelloException"></part>
</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 >
- <portType name="Example">
- <operation name="toSayHello" parameterOrder="userName">
- <input message="tns:toSayHello"></input>
- <output message="tns:toSayHelloResponse"></output>
- </operation>
- <operation name="sayHello" parameterOrder="person arg1">
- <input message="tns:sayHello"></input>
- <output message="tns:sayHelloResponse"></output>
- <fault message="tns:HelloException" name="HelloException"></fault>
- </operation>
- </portType>
<portType name="Example">
<operation name="toSayHello" parameterOrder="userName">
<input message="tns:toSayHello"></input>
<output message="tns:toSayHelloResponse"></output>
</operation>
<operation name="sayHello" parameterOrder="person arg1">
<input message="tns:sayHello"></input>
<output message="tns:sayHelloResponse"></output>
<fault message="tns:HelloException" name="HelloException"></fault>
</operation>
</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 >
- <binding name="ExamplePortBinding" type="tns:Example">
- <soap:binding
- transport="http://schemas.xmlsoap.org/soap/http"
- style="rpc"></soap:binding>
- <operation name="toSayHello">
- <soap:operation soapAction="sayHello"></soap:operation>
- <input>
- <soap:body use="literal"
- namespace="http://www.jsoso.com/wstest"></soap:body>
- </input>
- <output>
- <soap:body use="literal"
- namespace="http://www.jsoso.com/wstest"></soap:body>
- </output>
- </operation>
- <operation name="sayHello">
- <soap:operation soapAction="sayHello"></soap:operation>
- <input>
- <soap:body use="literal"
- namespace="http://www.jsoso.com/wstest"></soap:body>
- </input>
- <output>
- <soap:body use="literal"
- namespace="http://www.jsoso.com/wstest"></soap:body>
- </output>
- <fault name="HelloException">
- <soap:fault name="HelloException" use="literal"></soap:fault>
- </fault>
- </operation>
- </binding>
<binding name="ExamplePortBinding" type="tns:Example">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="rpc"></soap:binding>
<operation name="toSayHello">
<soap:operation soapAction="sayHello"></soap:operation>
<input>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</input>
<output>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</output>
</operation>
<operation name="sayHello">
<soap:operation soapAction="sayHello"></soap:operation>
<input>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</input>
<output>
<soap:body use="literal"
namespace="http://www.jsoso.com/wstest"></soap:body>
</output>
<fault name="HelloException">
<soap:fault name="HelloException" use="literal"></soap:fault>
</fault>
</operation>
</binding>
<binding>標籤是完整描寫敘述協議、序列化和編碼的地方,<types>,<message>和<portType>標籤處理抽象的數據內容,而<binding>標籤是處理傳輸數據的物理實現。
<binding>標籤把前三部分的抽象定義詳細化。
首先<binding>標籤使用<soap:binding>的transport和style屬性定義了Web Service的通信協議HTTP和SOAP的請求風格RPC。其次<operation>子標籤將portType中定義的operation同SOAP的請求綁定,定義了操做名稱soapAction,輸出輸入參數和異常的編碼方式及命名空間。
WSDL服務地址綁定元素:< service >
- <service name="Example">
- <port name="ExamplePort" binding="tns:ExamplePortBinding">
- <soap:address location="http://localhost:8080/hello"></soap:address>
- </port>
- </service>
<service name="Example">
<port name="ExamplePort" binding="tns:ExamplePortBinding">
<soap:address location="http://localhost:8080/hello"></soap:address>
</port>
</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類代碼
- package org.jsoso.jws.server;
-
- import java.util.ArrayList;
- import javax.jws.WebMethod;
- import javax.jws.WebParam;
- import javax.jws.WebResult;
- import javax.jws.WebService;
- import javax.jws.WebParam.Mode;
- import javax.jws.soap.SOAPBinding;
- /
- * 提供WebService服務的類
- */
- @WebService(name="Example", targetNamespace="http://www.jsoso.com/wstest", serviceName="Example")
- @SOAPBinding(style=SOAPBinding.Style.RPC)
- public class Example {
- private ArrayList<Person> persons = new ArrayList<Person>();;
-
-
-
-
-
-
- @WebMethod(operationName="toSayHello",action="sayHello",exclude=false)
- @WebResult(name="returnWord")
- public String sayHello(@WebParam(name="userName")String userName) {
- return "Hello:" + userName;
- }
-
-
-
-
-
-
-
- @WebMethod(operationName="sayHello", action="sayHello")
- @WebResult(partName="personList")
- public Person[] sayHello(@WebParam(partName="person", mode=Mode.IN)Person person,
- String userName) throws HelloException {
- if (person == null || person.getName() == null) {
- throw new HelloException("說hello出錯,對像爲空。。");
- }
- System.out.println(person.getName() + " 對 " + userName + " 說:Hello,我今年" + person.getAge() + "歲");
- persons.add(person);
- return persons.toArray(new Person[0]);
- }
- }
package org.jsoso.jws.server;
import java.util.ArrayList;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.WebParam.Mode;
import javax.jws.soap.SOAPBinding;
/
* 提供WebService服務的類
*/
@WebService(name="Example", targetNamespace="http://www.jsoso.com/wstest", serviceName="Example")
@SOAPBinding(style=SOAPBinding.Style.RPC)
public class Example {
private ArrayList<Person> persons = new ArrayList<Person>();;
/**
*
* 返回一個字符串
* @param userName
* @return
*/
@WebMethod(operationName="toSayHello",action="sayHello",exclude=false)
@WebResult(name="returnWord")//本身定義該方法返回值在WSDL中相關的描寫敘述
public String sayHello(@WebParam(name="userName")String userName) {
return "Hello:" + userName;
}
/**
* web services 方法的返回值與參數的類型不能爲接口
* @param person
* @return
* @throws HelloException
*/
@WebMethod(operationName="sayHello", action="sayHello")
@WebResult(partName="personList")
public Person[] sayHello(@WebParam(partName="person", mode=Mode.IN)Person person,
String userName) throws HelloException {
if (person == null || person.getName() == null) {
throw new HelloException("說hello出錯,對像爲空。。");
}
System.out.println(person.getName() + " 對 " + userName + " 說:Hello,我今年" + person.getAge() + "歲");
persons.add(person);
return persons.toArray(new Person[0]);
}
}
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 服務:
- package org.jsoso.jws.server;
-
- import java.util.LinkedList;
- import java.util.List;
- import javax.xml.ws.Binding;
- import javax.xml.ws.Endpoint;
- import javax.xml.ws.handler.Handler;
-
-
-
-
- public class StartServer {
-
-
-
-
- public static void main(String[] args) {
-
-
-
- Example serverBean = new Example();
-
-
-
- Endpoint endpoint =
- Endpoint.publish("http://localhost:8080/hello", serverBean);
- Binding binding = endpoint.getBinding();
-
-
-
-
- List<Handler> handlerChain = new LinkedList<Handler>();
- handlerChain.add(new TraceHandler());
- binding.setHandlerChain(handlerChain);
- System.out.println("服務已啓動 http://localhost:8080/hello");
- }
- }
package org.jsoso.jws.server;
import java.util.LinkedList;
import java.util.List;
import javax.xml.ws.Binding;
import javax.xml.ws.Endpoint;
import javax.xml.ws.handler.Handler;
/**
* @author zsy 啓動web services服務
*/
public class StartServer {
/**
* @param args
*/
public static void main(String[] args) {
/*
* 生成Example 服務實例
*/
Example serverBean = new Example();
/*
* 公佈Web Service到http://localhost:8080/hello地址
*/
Endpoint endpoint =
Endpoint.publish("http://localhost:8080/hello", serverBean);
Binding binding = endpoint.getBinding();
/*
* 設置一個SOAP協議處理棧
* 這裏就簡單得打印SOAP的消息文本
*/
List<Handler> handlerChain = new LinkedList<Handler>();
handlerChain.add(new TraceHandler());
binding.setHandlerChain(handlerChain);
System.out.println("服務已啓動 http://localhost:8080/hello");
}
}
在控制檯執行這個類,就可以使用URL :http://localhost:8080/hello?wsdl 瀏覽到上文所描寫敘述的WSDL的全文了。這說明您的第一個Web Service應用公佈成功!
構建Web Serviceclient
使用JavaSE6.0構建Web Service的client是一件至關簡單的事。這裏咱們要使用到JDK中的還有一個命令行工具wsimport。在控制檯下輸入下面命令:
引用
wsimport -d ./bin -s ./src -p org.jsoso.jws.client.ref http://localhost:8080/hello?wsdl
就能夠在包org.jsoso.jws.client.ref中生成client的存根及框架文件。當中咱們要使用的類僅僅有兩個:服務類Example_Service和本地接口Example。編寫例如如下client,就能夠調用Web Service服務:
- package org.jsoso.jws.client;
-
- import org.jsoso.jws.client.ref.*;
-
- public class RunClient {
-
-
-
-
- public static void main(String[] args) {
-
- Example_Service service = new Example_Service();
-
- Example server = (Example) service.getExamplePort();
- try {
-
- System.out.println("輸入toSayHello的返回值——" + server.toSayHello("阿土"));
- Person person = new Person();
- person.setName("阿土");
- person.setAge(25);
-
- server.sayHello(person, "機器人");
-
- person = new Person();
- person.setName("aten");
- person.setAge(30);
-
- PersonArray list = server.sayHello(person, "機器人");
-
- System.out.println("/n下面輸入sayHello的返回值——");
- for (Person p : list.getItem()) {
- System.out.println(p.getName() + ":" + p.getAge());
- }
- } catch (HelloException_Exception e) {
- e.printStackTrace();
- }
- }
- }
package org.jsoso.jws.client;
import org.jsoso.jws.client.ref.*;
public class RunClient {
/**
* @param args
*/
public static void main(String[] args) {
//初始化服務框架類
Example_Service service = new Example_Service();
//或者本地服務藉口的實例
Example server = (Example) service.getExamplePort();
try {
//調用web service的toSayHello方法
System.out.println("輸入toSayHello的返回值——" + server.toSayHello("阿土"));
Person person = new Person();
person.setName("阿土");
person.setAge(25);
//調用web service的sayHello方法
server.sayHello(person, "機器人");
person = new Person();
person.setName("aten");
person.setAge(30);
//調用web service的sayHello方法
PersonArray list = server.sayHello(person, "機器人");
//輸出返回值
System.out.println("/n下面輸入sayHello的返回值——");
for (Person p : list.getItem()) {
System.out.println(p.getName() + ":" + p.getAge());
}
} catch (HelloException_Exception e) {
e.printStackTrace();
}
}
}
屆此,本次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中的方法有申明拋出異常,這一步是必需的,不然server沒法綁定該對像。此外,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文件生成client存根及框架,負責與Web Service server通訊,並在將其封裝成實例,client可以直接使用,就像使用本地實例同樣。對Java而言,wsimport幫助程序猿生存調用web service所需要的client類文件.java和.class。要提醒指出的是,wsimport可以用於非Java的server端,如:server端或許是C#編寫的web service,經過wsimport則生成Java的client實現。
命令參數說明:
- -d 生成client運行類的class文件的存放文件夾
- -s 生成client運行類的源文件的存放文件夾
- -p 定義生成類的包名
命令範例:wsimport -d ./bin -s ./src -p org.jsoso.jws.client.ref http://localhost:8080/hello?wsdl