在“使用 WSDL 部署 Web 服務”系列中,Bilal 將研究建立、部署和發布 Web 服務的所有主要技術方面 — 從 Web 服務描述語言(WSDL),到簡易物件存取通訊協定 (SOAP)(SOAP)以及通用描述、探索與整合(UDDI)註冊中心。第 1 部分集中講述了 WSDL 建立:您將學習如何手工建立 WSDL 介面,然後將您的成果與 WSDL 編寫工具的輸出作比較。 可互操作的基於 Web 分布式應用程式的思想並非新近出現。僅舉一例,電子資料交換(EDI)市場需求早在 B2B 線上電子商務獲得任何有意義的實現之前就存在了 — 並且隨著 B2B 電子市場的普及,互通性已經成為最迫切的 EDI 需求。
以任何線上電子市場為例。存在著許多企業,各自提供特有的“服務( services)”(讓我們稱之為“Web 服務(Web services)”)。在當今的電子商務中,尚不存在一種機制,使一個業務能自動探索其預期夥伴提供的服務。所謂的 下一代 .com 還是提供這種自動的發現機制。
什麼是 WSDL。 這種新的 .com 需要一種解決方案來描述它所提供的服務(Web 服務)。具體而言,這意味著您需要一種格式或某種類型的文法,使您可以通過使用它們來描述下列問題的答案:
您的線上業務提供什麼服務。 您如何調用商務服務。 當使用者調用您的商務服務時,該商務服務需要他/她提供什麼資訊。 使用者將如何提供這些必需資訊。 服務將以什麼格式發送返回給使用者的資訊。
很幸運,WSDL 提供了完成所有這些作業的機制。
WSDL 和 SOAP 為更好理解 WSDL 是如何工作的,我將首先描述 SOAP 和 HTTP 是如何使用 WSDL 工作的。WSDL 的用途是“描述”您的 Web 服務。業務之間將通過交換 WSDL 檔案來理解對方的服務。一旦知道您夥伴的服務並希望調用它們,SOAP 就派上用場了。可以將服務看作是通過 SOAP 訪問的對象。
最有可能的情況是,您將通過網際網路或電子郵件與潛在夥伴通訊。當然,網際網路使用 HTTP 而電子郵件以 SMTP 方式工作,這使得 HTTP 和 SMTP 成為作為 SOAP 的“傳輸服務提供者”的有利候選人。
WSDL 編寫 現在,我將講述為 Web 服務編寫 WSDL 的過程。目的是公開現有的 Web 服務。您所處的情況也許就是下列情況之一:
您有一個現存的服務(例如,一個網站),並希望表示它的功能性。 您有一個 WSDL,並且希望依照已經決定表示的功能性來實現 Web 服務器端的邏輯。(有些人也許會認為這是一個不可能的方案,但是 UDDI 的指紋概念使它變得極為可能;我將在本系列的第四部分討論 UDDI)。 您正在從零開始,並且既無網站又無 WSDL 介面。
本文中所涵蓋的資訊適用於這些可能性中的任意一種或全部。
WSDL 編寫的四個步驟 我將把 WSDL 編寫分成四個簡單步驟。遵循每個步驟,您的 Web 服務將準備就緒用於部署。
步驟 1:服務介面 您將構建一個行動電話銷售公司的服務介面作為樣本項目(我將這個服務稱為 MobilePhoneService)。該公司銷售不同型號的行動電話,所以公司 Web 服務的後端資料存放區庫中將包含一個具有兩列(model number 和 price)的表格。(為了將焦點保持在 WSDL 本身,我保持該表格的簡單性)。有兩個關於要使用 WSDL 表示的服務的方法:
getListOfModels () getPrice (modelNumber)
GetListOfModels 方法提供了一個字串數組,其中每個字串表示一種行動電話的型號。 GetPrice 獲得型號,然後返回它的價格。WSDL 將這些方法作為操作調用。現在將開始構建“WSDL 介面檔案(WSDL interface file)”。
每個 WSDL 檔案的根項目都是 ,必須在其中提供服務的完整描述。首先,必須在 元素中提供各種名稱空間的聲明。三個必須做的外部名稱空間聲明是 WSDL、SOAP 和 XSD(XML 模式定義)。還有一個名稱空間 — TNS,它指您的 MobilePhoneService(這表示 TNS(targetNamespace 的縮寫)包含專為 MobilePhoneService 定義的所有元素和屬性的名稱)。但是 WSDL 是您將在 WSDL 編寫中使用得最多的主要名稱空間。在本系列文章中使用到其它名稱空間時,我將提到它們的效用。
關於名稱空間只要注意一點:WSDL 廣泛地使用名稱空間這一概念。我鼓勵您到 W3C 的官方網站去學習關於名稱空間的更多知識(請參閱參考資料)。WSDL 是這種思想的一種實現,因為名稱空間提供了無限的靈活性,而這恰恰是用於電子資料交換的可移植格式所需要的。
元素包含一個或多個 元素,實際上,每個元素都是您希望表示的一系列 operation。或者,您也可以將單個 portType 元素看作是將各種方法組成類的一個邏輯分組。例如,如果您的供應鏈管理解決方案需要在客戶和供應商之間進行互動,您最可能做的是分別定義與他們互動的功能性;也就是說,您將為使用者和供應商各定義一個 portType。應該將每個 portType 稱為服務,因此整個 WSDL 檔案將成為一個服務集合。
必須為每個服務提供一個名稱。在本例中,僅有一個服務(因此只有一個 )。 需要使用該 portType 元素的 name 屬性為行動電話銷售服務指定名稱。
在每個服務內可以有幾個方法、或者 operation,WSDL 通過 元素來引用它們。樣本應用程式有兩個要表示的方法:getListOfModels 和 getPrice。因此,您需要提供兩個 元素,每個元素有一個 name。 我已經使用 元素的 name 屬性命名了每個操作。
此時,WSDL 檔案看上去象清單 1。
清單 1:定義操作
targetNamespace="www.mobilephoneservice.com/MobilePhoneService-interface" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.mobilephoneservice.com/MobilePhoneService" xmlns:xsd="http://www.w3.org/1999/XMLSchema">
....... .......
....... .......
步驟 2:指定參數 定義好操作(或方法)以後,現在需要指定將向它們發送和從它們返回的參數。在 WSDL 術語中,所有參數稱為“訊息”。認為您是在遞送訊息而結果得到返回的訊息是有用的。方法調用是這樣一種操作:它準備返回“訊息”來響應進入的訊息。
請回憶,在第一步驟中有兩個操作要表示。第一個操作 getListOfModels 不必獲得任何參數並且返回一個字串數組,其中每個字串表示行動電話的型號。因此,必須定義一個包含字串數組的 元素。
看看清單 2 中的各種 元素。其中的第一個元素有一個等於 ListOfPhoneModels 的名稱屬性(該訊息的邏輯名稱),以及名稱為 models 的單個 元素,這意味著該 ListOfPhoneModels 是一個“只含有一個 part 的”訊息,其中僅有的這個 part 的名稱是“models”。訊息可以有任意多個 part — 只要為它們起不同的名稱,以唯一標識。
我已包括了 元素的另一個屬性,它就是 type。將這個“type”屬性當作 C++ 或 Java 中的資料類型。我已經將 models 的資料類型指定為 tns:Vector。(請回憶,我在 根項目中指定了一些名稱空間,其中之一是 tns。)這個類型即指 MobilePhoneService 名稱空間。這意味著當編寫 WSDL 時,您可以建立自己的名稱空間。現在您也許會問兩個邏輯問題:為什麼。和怎麼做。
要回答為什麼,讓我們以 getListOfModels 操作返回的字串數組為例。WSDL 使用 XML 模式定義(XSD)定義的一些未經處理資料類型(諸如 int、float、long、short、byte、string、Boolean 等等),並允許您直接使用它們,或者以這些未經處理資料類型構建複雜資料類型後,在訊息中使用它們。這就是為什麼當引用複雜資料類型時,您需要定義自己的名稱空間。在本例中,需要為 array of strings 構建一個複雜資料類型。
現在來看怎麼做問題,您將使用 XSD 建立自己的名稱空間。為實現這個目的,我在 元素中使用了 xsd:complexType 元素用來定義稱為 Vector 的資料類型。Vector 使用兩個未經處理資料類型:string(元素資料)和 Integer(元素計數)。因此,Vector 成為名稱空間的一部分並可以通過別名 tns 來引用。
在清單 2 中,我以類似的方式定義了另外兩個訊息 PhoneModel 和 PhoneModelPrice。這兩個訊息只使用了 xsd 名稱空間中的未經處理資料類型 string,因此您不必為使用它們而定義任何更複雜的資料類型。
您也許已經注意到當建立 元素時,沒有指定這些訊息是進入參數還是傳回值。這是一個您將在 元素內的 元素中完成的工作。因此,正如您在清單 2 中所看到的,我已經將 和 元素都添加到這兩個操作中。每個 input 元素通過訊息名來引用它並將它當作使用者調用該操作時要提供的參數。類似地,每個 元素引用一個訊息;它將該訊息當作操作調用的傳回值。
至今,清單 2 準確地限定了目前的討論的範圍。
步驟 3:訊息傳遞和傳輸 我以一種抽象方式定義了操作和訊息,而不考慮實現的細節。實際上,WSDL 的任務是定義或描述 Web 服務,然後提供一個對外部架構的引用來定義 WSDL 使用者將如何?這些服務。可以將這個架構當作 WSDL 抽象定義和它們的實現之間的“綁定(binding)”。
當前,最流行的綁定(binding)技術是使用簡易物件存取通訊協定 (SOAP)(SOAP)。WSDL 將指定能夠訪問 Web 服務實際實現的 SOAP 伺服器,並且從那時起 SOAP 的整個任務就是將使用者從 WSDL 檔案帶到它的實現。SOAP 是本系列文章中下一部分的主題,所以我將暫時避免討論 SOAP 細節而繼續集中講述 WSDL 編寫。
WSDL 編寫的第三個步驟是描述將 SOAP 與 WSDL 檔案綁定到一起的過程。您將把 元素包括到 元素內。這個 binding 元素應該有 name 和 type 屬性。name 將標識這個綁定而 type 將標識您希望與這個綁定相關聯的 portType(一組操作)。在清單 3 中,您會發現 元素的 name 與 元素的 type 屬性值相匹配。
WSDL binding 元素包含您將用於綁定用途的外部技術的聲明。因為正在使用 SOAP,所以這裡將使用 SOAP 的名稱空間。WSDL 術語中,對外部名稱空間的使用稱為 extensibility 元素。
在清單 3 中,您將看見一個空的 元素。該元素的用途是聲明將把 SOAP 作為綁定和傳輸服務使用。
元素有兩個屬性:style 和 transport。style 是一個可選屬性,它描述該綁定內操作的性質。transport 屬性指定 HTTP 作為該綁定將使用的層級較低的傳輸服務。
SOAP 客戶機將從 WSDL 檔案中讀取 SOAP 結構並與另一端的 SOAP 伺服器協調,所以必須特別關注 interoperability。我打算在本系列文章的第三部分詳細講述該問題。
在空的 元素後面,有兩個 WSDL 元素,分別表示步驟 1 的操作。每個 元素提供各自操作的綁定細節。因此,我提供了另一個 extensibility 元素,即 (仍然是一個空元素,與它發生的那個操作相關)。該 元素有一個 soapAction 屬性,SOAP 客戶機將使用該屬性建立 SOAP 請求。
請回憶步驟 2 中,getListOfModels 操作只有輸出而無任何輸入。因此,必須為該操作提供一個 元素。該輸出包含 元素(仍然是一個空元素,與它發生的那個操作相關)。SOAP 客戶機需要該資訊來建立 SOAP 請求。 的名稱空間屬性值應該與您將部署到 SOAP 伺服器上的 service 的名稱相對應,SOAP 伺服器將在在本系列文章的下一部分中講述。
您已幾乎要完成步驟 3 了。只要將下一個操作複製到這個操作的後面,您將完成清單 3。
步驟 4:概括 您已經產生了一個完整描述服務 interface 的 WSDL 檔案。現在,WSDL 需要一個附加步驟來建立該 WSDL 檔案的概要。WSDL 將該檔案稱為 implementation 檔案,在本系列文章的第四部分中,當您在 UDDI 註冊中心發布 Web 服務時,會使用它。請看清單 4 — 這個 WSDL 實現檔案。它的主要特性如下:
除了清單 4(實現檔案)引用不同的 targetNamespace 去引用實現檔案以外, 根項目和清單 3(WSDL 介面檔案)中的完全相同。 有一個 元素,該元素引用清單 3 的介面檔案(檔案名稱 MobilePhoneService-interface.wsdl)和它的名稱空間。 有一個 標記,其中有一個表示該服務的邏輯名 name。在 service 元素內有一個引用在清單 3 中建立的 SOAP 綁定的 port 元素。
將 IBM 的 Web Services ToolKit(WSTK)用於 WSDL 編寫 現在,Web 服務已經完全就緒用於部署。我已經展示了如何手工建立這些檔案(使用象 emacs 這樣的簡單文字編輯器)。可以使用諸如 IBM 的 WSTK(請參閱參考資料以獲得該工具箱以及本文提到的其它參考資料的連結)之類的 Web 服務編寫工具來產生相同的這些檔案。
WSTK 可以使用嚮導協助過程來產生這些檔案。使用者可以產生與我在以上教程中示範的同樣兩種方法的 WSDL 檔案,並將 WSTK 檔案和清單 3 和 4 中的 WSDL 檔案作比較。
您將注意到下列差異:
WSTK 依照邏輯規則建立了所有名稱屬性;在本樣本中,我使用了自己視為方便的名稱。 WSTK 為每個操作至少產生一個 input 標記,即使該操作不必獲得任何輸入。listAllPhoneModels 操作沒有任何 input 元素,但是如果使用 WSTK 產生相同檔案,它將因為包含這個方法的一個空 input 元素。 WSTK 產生了除已產生的兩個檔案以外的第三個檔案。這第三個檔案是 SOAP 引擎用於服務部署的 SOAP 部署描述符。我將在本系列文章中討論服務部署。
在這部分中,我示範了手工進行 WSDL 編寫以建立介面和實現檔案,並與 IBM 的 Web Services ToolKit 產生的檔案作了比較。在本系列的下一部分中,我將討論在 SOAP 伺服器上部署這個 WSDL 服務。