Bilal Siddiqui CEO, WAP Monster 2001 年 11 月 在“使用 WSDL 部署 Web 服務(wù)”系列中,Bilal 將研究創(chuàng )建、部署和發(fā)布 Web 服務(wù)的所有主要技術(shù)方面 ― 從 Web 服務(wù)描述語(yǔ)言(WSDL),到簡(jiǎn)單對象訪(fǎng)問(wèn)協(xié)議(SOAP)以及通用描述、發(fā)現和集成(UDDI)注冊中心。第 1 部分集中講述了 WSDL 創(chuàng )建:您將學(xué)習如何手工創(chuàng )建 WSDL 接口,然后將您的成果與 WSDL 編寫(xiě)工具的輸出作比較。 可互操作的基于 Web 分布式應用程序的思想并非新近出現。僅舉一例,電子數據交換(EDI)市場(chǎng)需求早在 B2B 在線(xiàn)電子商務(wù)獲得任何有意義的實(shí)現之前就存在了 ― 并且隨著(zhù) B2B 電子市場(chǎng)的普及,互操作性已經(jīng)成為最迫切的 EDI 需求。 以任何在線(xiàn)電子市場(chǎng)為例。存在著(zhù)許多企業(yè),各自提供特有的“服務(wù)( services )”(讓我們稱(chēng)之為“Web 服務(wù)( Web services )”)。在當今的電子商務(wù)中,尚不存在一種機制,使一個(gè)業(yè)務(wù)能自動(dòng)發(fā)現其預期伙伴提供的服務(wù)。所謂的 下一代 .com還是提供這種自動(dòng)的發(fā)現機制。 什么是 WSDL? 這種新的 .com 需要一種解決方案來(lái)描述它所提供的服務(wù)(Web 服務(wù))。具體而言,這意味著(zhù)您需要一種格式或某種類(lèi)型的語(yǔ)法,使您可以通過(guò)使用它們來(lái)描述下列問(wèn)題的答案: - 您的在線(xiàn)業(yè)務(wù)提供什么服務(wù)?
- 您如何調用業(yè)務(wù)服務(wù)?
- 當用戶(hù)調用您的業(yè)務(wù)服務(wù)時(shí),該業(yè)務(wù)服務(wù)需要他/她提供什么信息?
- 用戶(hù)將如何提供這些必需信息?
- 服務(wù)將以什么格式發(fā)送返回給用戶(hù)的信息?
很幸運,WSDL 提供了完成所有這些作業(yè)的機制。 WSDL 和 SOAP 為更好理解 WSDL 是如何工作的,我將首先描述 SOAP 和 HTTP 是如何使用 WSDL 工作的。WSDL 的用途是“描述”您的 Web 服務(wù)。業(yè)務(wù)之間將通過(guò)交換 WSDL 文件來(lái)理解對方的服務(wù)。一旦知道您伙伴的服務(wù)并希望調用它們,SOAP 就派上用場(chǎng)了??梢詫⒎?wù)看作是通過(guò) SOAP 訪(fǎng)問(wèn)的對象。 最有可能的情況是,您將通過(guò)因特網(wǎng)或電子郵件與潛在伙伴通信。當然,因特網(wǎng)使用 HTTP 而電子郵件以 SMTP 方式工作,這使得 HTTP 和 SMTP 成為作為 SOAP 的“傳輸服務(wù)提供者”的有利候選人。 WSDL 編寫(xiě) 現在,我將講述為 Web 服務(wù)編寫(xiě) WSDL 的過(guò)程。目的是公開(kāi)現有的 Web 服務(wù)。您所處的情況也許就是下列情況之一: - 您有一個(gè)現存的服務(wù)(例如,一個(gè)網(wǎng)站),并希望表示它的功能性。
- 您有一個(gè) WSDL,并且希望依照已經(jīng)決定表示的功能性來(lái)實(shí)現 Web服務(wù)器端的邏輯。(有些人也許會(huì )認為這是一個(gè)不可能的方案,但是 UDDI 的指紋概念使它變得極為可能;我將在本系列的第四部分討論 UDDI)。
- 您正在從零開(kāi)始,并且既無(wú)網(wǎng)站又無(wú) WSDL 界面。
本文中所涵蓋的信息適用于這些可能性中的任意一種或全部。 WSDL 編寫(xiě)的四個(gè)步驟 我將把 WSDL 編寫(xiě)分成四個(gè)簡(jiǎn)單步驟。遵循每個(gè)步驟,您的 Web 服務(wù)將準備就緒用于部署。 步驟 1:服務(wù)接口 您將構建一個(gè)移動(dòng)電話(huà)銷(xiāo)售公司的服務(wù)接口作為樣本項目(我將這個(gè)服務(wù)稱(chēng)為 MobilePhoneService )。該公司銷(xiāo)售不同型號的移動(dòng)電話(huà),所以公司 Web 服務(wù)的后端數據存儲庫中將包含一個(gè)具有兩列( model number 和 price )的表格。(為了將焦點(diǎn)保持在 WSDL 本身,我保持該表格的簡(jiǎn)單性)。有兩個(gè)關(guān)于要使用 WSDL 表示的服務(wù)的方法: - getListOfModels ()
- getPrice (modelNumber)
GetListOfModels 方法提供了一個(gè)字符串數組,其中每個(gè)字符串表示一種移動(dòng)電話(huà)的型號。 GetPrice 獲得型號,然后返回它的價(jià)格。WSDL 將這些方法作為操作調用?,F在將開(kāi)始構建“WSDL 接口文件( WSDL interface file )”。
每個(gè) WSDL 文件的根元素都是 <definitions> ,必須在其中提供服務(wù)的完整描述。首先,必須在 <definitions> 元素中提供各種名稱(chēng)空間的聲明。三個(gè)必須做的外部名稱(chēng)空間聲明是 WSDL、SOAP 和 XSD(XML 模式定義)。還有一個(gè)名稱(chēng)空間 ― TNS,它指您的 MobilePhoneService(這表示 TNS(targetNamespace 的縮寫(xiě))包含專(zhuān)為 MobilePhoneService 定義的所有元素和屬性的名稱(chēng))。但是 WSDL 是您將在 WSDL 編寫(xiě)中使用得最多的主要名稱(chēng)空間。在本系列文章中使用到其它名稱(chēng)空間時(shí),我將提到它們的效用。 關(guān)于名稱(chēng)空間只要注意一點(diǎn):WSDL 廣泛地使用名稱(chēng)空間這一概念。我鼓勵您到 W3C 的官方網(wǎng)站去學(xué)習關(guān)于名稱(chēng)空間的更多知識(請參閱 參考資料)。WSDL 是這種思想的一種實(shí)現,因為名稱(chēng)空間提供了無(wú)限的靈活性,而這恰恰是用于電子數據交換的可移植格式所需要的。 <definitions> 元素包含一個(gè)或多個(gè) <portType> 元素,實(shí)際上,每個(gè)元素都是您希望表示的一系列 operation ?;蛘?,您也可以將單個(gè) portType 元素看作是將各種方法組成類(lèi)的一個(gè)邏輯分組。例如,如果您的供應鏈管理解決方案需要在客戶(hù)和供應商之間進(jìn)行交互,您最可能做的是分別定義與他們交互的功能性;也就是說(shuō),您將為用戶(hù)和供應商各定義一個(gè) portType。應該將每個(gè) portType 稱(chēng)為 服務(wù),因此整個(gè) WSDL 文件將成為一個(gè)服務(wù)集合。
必須為每個(gè)服務(wù)提供一個(gè)名稱(chēng)。在本例中,僅有一個(gè)服務(wù)(因此只有一個(gè) <portType> )。 需要使用該 portType 元素的 name 屬性為移動(dòng)電話(huà)銷(xiāo)售服務(wù)指定名稱(chēng)。 在每個(gè)服務(wù)內可以有幾個(gè)方法、或者 operation ,WSDL 通過(guò) <operation> 元素來(lái)引用它們。樣本應用程序有兩個(gè)要表示的方法: getListOfModels 和 getPrice 。因此,您需要提供兩個(gè) <operation> 元素,每個(gè)元素有一個(gè) name 。 我已經(jīng)使用 <operation> 元素的 name 屬性命名了每個(gè)操作。 此時(shí),WSDL 文件看上去象 清單 1。 清單 1:定義操作
<?xml version="1.0" encoding="UTF-8" ?><definitions name="MobilePhoneService" 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"> <portType name="MobilePhoneService_port"> <operation name="getListOfModels "> ....... ....... </operation> <operation name="getPrice"> ....... ....... </operation> </portType></definitions>
|
步驟 2:指定參數 定義好操作(或方法)以后,現在需要指定將向它們發(fā)送和從它們返回的參數。在 WSDL 術(shù)語(yǔ)中,所有參數稱(chēng)為“消息”。認為您是在遞送消息而結果得到返回的消息是有用的。方法調用是這樣一種操作:它準備返回“消息”來(lái)響應進(jìn)入的消息。 請回憶,在第一步驟中有兩個(gè)操作要表示。第一個(gè)操作 getListOfModels 不必獲得任何參數并且返回一個(gè)字符串數組,其中每個(gè)字符串表示移動(dòng)電話(huà)的型號。因此,必須定義一個(gè)包含字符串數組的 <message> 元素。 看看 清單 2 中的各種 <message> 元素。其中的第一個(gè)元素有一個(gè)等于 ListOfPhoneModels 的名稱(chēng)屬性(該消息的邏輯名稱(chēng)),以及名稱(chēng)為 models 的單個(gè) <part> 元素,這意味著(zhù)該 ListOfPhoneModels 是一個(gè)“只含有一個(gè) part 的”消息,其中僅有的這個(gè) part 的名稱(chēng)是“models”。消息可以有任意多個(gè) part ― 只要為它們起不同的名稱(chēng),以唯一標識。 我已包括了 <part> 元素的另一個(gè)屬性,它就是 type 。將這個(gè)“type”屬性當作 C++ 或 Java 中的數據類(lèi)型。我已經(jīng)將 models 的數據類(lèi)型指定為 tns:Vector。(請回憶,我在 <definitions> 根元素中指定了一些名稱(chēng)空間,其中之一是 tns 。)這個(gè)類(lèi)型即指 MobilePhoneService 名稱(chēng)空間。這意味著(zhù)當編寫(xiě) WSDL 時(shí),您可以創(chuàng )建自己的名稱(chēng)空間?,F在您也許會(huì )問(wèn)兩個(gè)邏輯問(wèn)題:為什么?和怎么做? 要回答 為什么,讓我們以 getListOfModels 操作返回的字符串數組為例。WSDL 使用 XML 模式定義(XSD)定義的一些原始數據類(lèi)型(諸如 int、float、long、short、byte、string、Boolean 等等),并允許您直接使用它們,或者以這些原始數據類(lèi)型構建復雜數據類(lèi)型后,在消息中使用它們。這就是為什么當引用復雜數據類(lèi)型時(shí),您需要定義自己的名稱(chēng)空間。在本例中,需要為 array of strings 構建一個(gè)復雜數據類(lèi)型。 現在來(lái)看 怎么做問(wèn)題,您將使用 XSD 創(chuàng )建自己的名稱(chēng)空間。為實(shí)現這個(gè)目的,我在 <types> 元素中使用了 xsd:complexType 元素用來(lái)定義稱(chēng)為 Vector 的數據類(lèi)型。 Vector 使用兩個(gè)原始數據類(lèi)型:string(元素數據)和 Integer(元素計數)。因此, Vector 成為名稱(chēng)空間的一部分并可以通過(guò)別名 tns 來(lái)引用。 在 清單 2 中,我以類(lèi)似的方式定義了另外兩個(gè)消息 PhoneModel 和 PhoneModelPrice 。這兩個(gè)消息只使用了 xsd 名稱(chēng)空間中的原始數據類(lèi)型 string,因此您不必為使用它們而定義任何更復雜的數據類(lèi)型。 您也許已經(jīng)注意到當創(chuàng )建 <message> 元素時(shí),沒(méi)有指定這些消息是進(jìn)入參數還是返回值。這是一個(gè)您將在 <portType> 元素內的 <operation> 元素中完成的工作。因此,正如您在 清單 2 中所看到的,我已經(jīng)將 <input> 和 <output> 元素都添加到這兩個(gè)操作中。每個(gè) input 元素通過(guò)消息名來(lái)引用它并將它當作用戶(hù)調用該操作時(shí)要提供的參數。類(lèi)似地,每個(gè) <output> 元素引用一個(gè)消息;它將該消息當作操作調用的返回值。 至今, 清單 2準確地限定了目前的討論的范圍。 步驟 3:消息傳遞和傳輸 我以一種抽象方式定義了操作和消息,而不考慮實(shí)現的細節。實(shí)際上,WSDL 的任務(wù)是定義或描述 Web 服務(wù),然后提供一個(gè)對外部框架的引用來(lái)定義 WSDL 用戶(hù)將如何實(shí)現這些服務(wù)??梢詫⑦@個(gè)框架當作 WSDL 抽象定義和它們的實(shí)現之間的“綁定( binding )”。 當前,最流行的綁定( binding )技術(shù)是使用簡(jiǎn)單對象訪(fǎng)問(wèn)協(xié)議(SOAP)。WSDL 將指定能夠訪(fǎng)問(wèn) Web 服務(wù)實(shí)際實(shí)現的 SOAP 服務(wù)器,并且從那時(shí)起 SOAP 的整個(gè)任務(wù)就是將用戶(hù)從 WSDL 文件帶到它的實(shí)現。SOAP 是本系列文章中下一部分的主題,所以我將暫時(shí)避免討論 SOAP 細節而繼續集中講述 WSDL 編寫(xiě)。 WSDL 編寫(xiě)的第三個(gè)步驟是描述將 SOAP 與 WSDL 文件綁定到一起的過(guò)程。您將把 <binding> 元素包括到 <definitions> 元素內。這個(gè) binding 元素應該有 name 和 type 屬性。 name 將標識這個(gè)綁定而 type 將標識您希望與這個(gè)綁定相關(guān)聯(lián)的 portType(一組操作)。在 清單 3 中,您會(huì )發(fā)現 <portType> 元素的 name 與 <binding> 元素的 type 屬性值相匹配。 WSDL binding 元素包含您將用于綁定用途的外部技術(shù)的聲明。因為正在使用 SOAP,所以這里將使用 SOAP 的名稱(chēng)空間。WSDL 術(shù)語(yǔ)中,對外部名稱(chēng)空間的使用稱(chēng)為 extensibility 元素。 在 清單 3 中,您將看見(jiàn)一個(gè)空的 <soap:binding/> 元素。該元素的用途是聲明將把 SOAP 作為綁定和傳輸服務(wù)使用。 <soap:binding> 元素有兩個(gè)屬性:style 和 transport。style 是一個(gè)可選屬性,它描述該綁定內操作的性質(zhì)。transport 屬性指定 HTTP 作為該綁定將使用的級別較低的傳輸服務(wù)。
SOAP 客戶(hù)機將從 WSDL 文件中讀取 SOAP 結構并與另一端的 SOAP 服務(wù)器協(xié)調,所以必須特別關(guān)注 interoperability 。我打算在本系列文章的第三部分詳細講述該問(wèn)題。 在空的 <soap:binding/> 元素后面,有兩個(gè) WSDL <operation> 元素,分別表示步驟 1 的操作。每個(gè) <operation> 元素提供各自操作的綁定細節。因此,我提供了另一個(gè) extensibility 元素,即 <soap:operation/> (仍然是一個(gè)空元素,與它發(fā)生的那個(gè)操作相關(guān))。該 <soap:operation/> 元素有一個(gè) soapAction 屬性,SOAP 客戶(hù)機將使用該屬性創(chuàng )建 SOAP 請求。 請回憶步驟 2 中, getListOfModels 操作只有輸出而無(wú)任何輸入。因此,必須為該操作提供一個(gè) <output> 元素。該輸出包含 <soap:body/> 元素(仍然是一個(gè)空元素,與它發(fā)生的那個(gè)操作相關(guān))。SOAP 客戶(hù)機需要該信息來(lái)創(chuàng )建 SOAP 請求。 <soap:body/> 的名稱(chēng)空間屬性值應該與您將部署到 SOAP 服務(wù)器上的 service 的名稱(chēng)相對應,SOAP 服務(wù)器將在在本系列文章的下一部分中講述。 您已幾乎要完成步驟 3 了。只要將下一個(gè)操作復制到這個(gè)操作的后面,您將完成 清單 3。 步驟 4:概括 您已經(jīng)生成了一個(gè)完整描述服務(wù) interface 的 WSDL 文件?,F在,WSDL 需要一個(gè)附加步驟來(lái)創(chuàng )建該 WSDL 文件的概要。WSDL 將該文件稱(chēng)為 implementation 文件,在本系列文章的第四部分中,當您在 UDDI 注冊中心發(fā)布 Web 服務(wù)時(shí),會(huì )使用它。請看 清單 4― 這個(gè) WSDL 實(shí)現文件。它的主要特性如下: - 除了
清單 4(實(shí)現文件)引用不同的 targetNamespace 去引用實(shí)現文件以外, <definitions> 根元素和 清單 3(WSDL 接口文件)中的完全相同。 - 有一個(gè)
<import> 元素,該元素引用 清單 3的接口文件(文件名 MobilePhoneService-interface.wsdl)和它的名稱(chēng)空間。 - 有一個(gè)
<service> 標記,其中有一個(gè)表示該服務(wù)的邏輯名 name 。在 service 元素內有一個(gè)引用在 清單 3中創(chuàng )建的 SOAP 綁定的 port 元素。
將 IBM 的 Web Services ToolKit(WSTK)用于 WSDL 編寫(xiě) 現在,Web 服務(wù)已經(jīng)完全就緒用于部署。我已經(jīng)展示了如何手工創(chuàng )建這些文件(使用象 emacs 這樣的簡(jiǎn)單文本編輯器)??梢允褂弥T如 IBM 的 WSTK(請參閱 參考資料以獲得該工具箱以及本文提到的其它參考資料的鏈接)之類(lèi)的 Web 服務(wù)編寫(xiě)工具來(lái)生成相同的這些文件。 WSTK 可以使用向導幫助過(guò)程來(lái)生成這些文件。用戶(hù)可以生成與我在以上教程中演示的同樣兩種方法的 WSDL 文件,并將 WSTK 文件和 清單 3和 4中的 WSDL 文件作比較。 您將注意到下列差異: - WSTK
依照邏輯規則創(chuàng )建了所有名稱(chēng)屬性;在本示例中,我使用了自己視為方便的名稱(chēng)。 - WSTK 為每個(gè)操作至少生成一個(gè) input
標記,即使該操作不必獲得任何輸入。 listAllPhoneModels 操作沒(méi)有任何 input 元素,但是如果使用 WSTK 生成相同文件,它將因為包含這個(gè)方法的一個(gè)空 input 元素。 - WSTK 產(chǎn)生了除已生成的兩個(gè)文件以外的第三個(gè)文件。這第三個(gè)文件是
SOAP 引擎用于服務(wù)部署的 SOAP 部署描述符。我將在本系列文章中討論服務(wù)部署。
在這部分中,我演示了手工進(jìn)行 WSDL 編寫(xiě)以創(chuàng )建接口和實(shí)現文件,并與 IBM 的 Web Services ToolKit 生成的文件作了比較。在本系列的下一部分中,我將討論在 SOAP 服務(wù)器上部署這個(gè) WSDL 服務(wù)。 參考資料 關(guān)于作者 Bilal Siddiqui 是一位 XML 顧問(wèn)。自從 1995 年畢業(yè)于拉合爾工程技術(shù)大學(xué)(University of Engineering and Technology,Lahore)電子工程專(zhuān)業(yè)以后,他就開(kāi)始為工業(yè)控制系統設計各種軟件解決方案。稍后,他致力于 XML 方面并使用他在 C++ 編程中取得的經(jīng)驗來(lái)構建基于 Web 和 WAP 的 XML 處理工具、服務(wù)器端解析方案和服務(wù)應用程序??梢酝ㄟ^(guò)電子郵件( wap_monster@yahoo.com)向 Bilal 索取本文中包含的代碼文件的工作副本。 |
|