引言
開放式標準被企業用作降低高整合及維護費用的主要手段。現實中的各種異構軟體系統使得我們必須使用一些涉及開放式標準的策略,而 Web 服務很快就成為瞭解決這個難題的方法的一個重要部分。直到現在,要構造一個介面友好的 GUI 用戶端來與這些系統進行互動還是非常的單調乏味。這個問題的一個部分就是 Web 服務描述語言(Web Services Description Language ,WSDL)正趨向於成為服務端點的唯一描述語言,這有時使得遵守起來變得非常困難,尤其是對組織中的設計人員和使用者介面開發人員。Flex 是 Macromedia 開發的一個 Rich Internet Application 平台,它在使用者介面設計人員和更多傳統伺服器端開發人員之間搭了一座橋。傳統的背景程式員可以利用大量的迷人的可視控制、效能、布局、及現有的 Flash 組件,加上他們對服務端點的深厚知識,從而裝配出一個誘人的用戶端應用程式。在任何時候不管有什麼類型的資源在您的項目中可用,最後的結果都是可以容易地建立一個高互動及誘人的應用程式,它在 Web 服務中整合了您的投資。
理解 WSDL
為了在不同的 SOAP 服務端點間交換訊息(在 Flex 中,SOAP 訊息被限制成只能使用 HTTP 協議傳輸機制),Flex 通過引用 WSDL 文檔的 URL 來使用現有的 WSDL 定義。下表列舉了經常會在 WSDL 文檔中出現的元素:
表 1. 常見的 WSDL 元素
| 元素名 |
描述 |
| types |
定義了 Web 服務訊息可以使用的資料類型。 |
| message |
定義了 Web 服務操作中要傳輸的資料格式。 |
| portType |
定義了一個 Web 服務要提供的一個或多個操作。 |
| operation |
定義了輸入、輸出及錯誤訊息的組合。 |
| input |
指出了 Web 服務用戶端要(例如 Flex 應用程式)發生給 Web 服務的訊息。 |
| output |
指出了 Web 服務要發送給用戶端(例如 Flex 應用程式)的訊息。 |
| fault |
指出了處理訊息出錯時返回來的錯誤值。 |
| binding |
指出了與 Web 服務進行通訊時使用的網路通訊協定。現有 SOAP 綁定包括 HTTP GET、HTTP POST、以及 MIME 協議。Flex 現在只指出 SOAP 綁定。 |
| service |
定義連接埠集。每一個 service 元素對應一個 portType 元素,從而指定了訪問定義在 portType 元素中的操作的不同方法。 |
| port |
Web 服務端點,指出了綁定和網路地址間的關聯。 |
這些可以協助我們對這些元素怎樣在 WSDL 文檔共同定義不同的 Web 服務有一個統一的理解。 然而,Flex 設法隱藏了開發人員對 Web 服務定義的複雜性,而且對大多數人來說,能大概知道服務要提供哪些功能就已經非常足夠了。
還有一點非常重要,WSDL 提供了兩種截然不同的方式來描述服務作業:遠端程序呼叫(Remote Procedure Call,RPC)及面向文檔(document-oriented)的方式。對於一個 RPC 服務作業的 Flex 調用,它會發送一個 SOAP 訊息來指出要調用的操作及操作所需要的參數。而對於一個面向文檔式操作的 Flex 調用,它會發送一個封裝成 XML 文檔的 SOAP 訊息。Flex 對這兩種方式都提供了,但是由於它們使用了專門的標記,這暗示了這兩種方式之間有細微的差別。在文章的後面,作者會通過各種執行個體來詳細地解釋這兩種方式的使用。
在 Flex 中使用 Web 服務
在您的 Flex 應用程式中,聲明 Web 服務最基本的原則就是使用 <mx:WebService> MXML 標記(以 mx為首碼的 XML 標記是 MXML 命名空間的一部分,並用來構成一個 MXML 檔案)。比較典型的用法是,在這個標記上使用一個wsdl 屬性,通過它來指出要引用的 WSDL 文檔 URL。Flex 提供了一個專門的服務構想,用來移動這些聲明的某些標記到 flex-config.xml 文檔的專門塊中。Flex 文檔包含了這個專門服務的更詳細介紹。為了在整個 MXML 應用程式中都能指向它,可以在 <mx:WebService> 標記中使用 id 屬性來指出服務 ID。
<mx:WebService id="serviceID" wsdl="http://somehost/someService/service.wsdl"><mx:operation name="someOP" result="someResultHandler()"fault="someFaultHandler()"><mx:request><!-- parameters --></mx:request></mx:operation></mx:WebService>
|
相應的 ActionScript serviceID.send() 現在調用了這個 Web 服務功能。但有一點非常重要的是,當不帶參數地使用 send() 方法時,所有的參數綁定都應該在實際的 Web 服務定義中定義。換句話說,參數綁定應該使用 <mx:request> 標記中的一個 XML 資料模型來隱含關聯起來。
<mx:WebService id="serviceID" wsdl="http://somehost/someService/service.wsdl"><mx:operation name="someOP" result="someResultHandler()"fault="someFaultHandler()"><mx:request><param1>{input1.text}</param1><param2>{input2.text}</param2></mx:request></mx:operation></mx:WebService>
|
另一個綁定參數到這個服務調用的方法就是明確地傳送這些參數。一個明確地綁定這些參數的調用應該看上去像 serviceID.send(input1.text, input2.text) ,通過這個方法,我們不需要像前面描述的那樣使用 MXML 聲明中的 XML 資料模型。
您現在已經看見了從 Flex 應用程式中調用 Web 服務的機制,但是您怎樣處理這些調用結果呢?讓我們來更仔細地看看前面的聲明,您可以注意到了 <mx:operation> 標記上的 result和fault 屬性。這些引用 ActionScript 方法來處理調用結果和服務調用中可能發生的錯誤。這裡要強調的是上面描述的對您的 Web 服務的調用是一個非同步呼叫。這是一個要非常注意的不同點,因為您可能已經習慣了這樣的一種情況——一個方法調用返回後就意味著該方法正確執行完畢了。然而在您的 Flex 應用程式中,在 send() 方法後的語句會被馬上執行,而不必等待 Web 服務執行的返回。當 結果(result)處理器(在 operation 屬性中被引用)被通知 Web 服務已經執行完畢後,應用程式能處理服務調用的結果。而如果服務調用中出現了錯誤,則相關聯的fault 處理器會被通知。
如果順利的話,您正在對怎樣使通過使用 Flex 環境來整合您的 Web 服務能沒有那麼單調變得更清晰。 後面我們來看一些執行個體,它們描述了在 Web 服務聲明中的 WSDL 專門的 MXML 表明,這個我們在這部分沒有提及到。
WSDL 到 Flex 映射執行個體
關於這個執行個體
下面的執行個體覆蓋了使用 WSDL 來定義基於 SOAP 的 Web 服務的不同方法,以及 WSDL 定義怎樣映射到 MXML 的 Web 服務構造中。我們在前面部分提到了 Web 服務可以在 MXML 中使用參數綁定進行聲明。這意味著操作的參數可以作為 Web 服務聲明(在一個 XML 資料模型中)的一部分包含進來,如下:
<mx:WebService><mx:operation><mx:request><!--parameters here--></mx:request></mx:operation></mx:WebService>
|
在 <mx:operation> 元素中的 <mx:request> 元素包含了 XML 和 Flex 綁定的混合體,它們是構造訊息 SOAP 體內容的必要部分。
在這個執行個體中使用的 WSDL 檔案是通過 IBM WebSphere Application Developer V5.1 Web 服務嚮導(這個嚮導和 WebSphere Application Server 的 Web 服務支援都是基於 JSR 109 規範的)自動產生的。這個嚮導生產了 WSDL 檔案、類型映射、序列化器及部署 Web 服務到 WebSphere Application Server V5.X(我們這裡使用的是 V5.1)上需要的配置條目。雖然使用 WSDL 時有多種方法來聲明 Web 服務,但是下面的執行個體重點放在 WebSphere 工具生產的 WSDL 定義集上。
我們首先描述 WSDL 定義和 MXML Web 服務聲明(該聲明對任何 WSDL 檔案都是通用的)之間的映射。這些包括了 MXML 元素和相應的屬性,這些屬性的值不依賴於專門的 SOAP 綁定設定。然後,我們解釋更複雜的映射,它們依賴於操作方式(文檔還是 RPC)、使用的編碼機制(文字還是編碼)、參數的類型(簡單還是複雜)、以及參數的數量。
公用映射
使用 MXML 描述 Web 服務的第一步是選擇 Web 服務的 WSDL 定義檔案。您可以通過設定 <mx:WebService> 元素的 wsdl 屬性為 WSDL 檔案的 URL 來完成(在更新的 Flex 版本中,您可以使用服務的名稱來查詢 WSDL 的 URL)。然後您通過設定 <mx:WebService> 元素的 service和port屬性來選擇目標服務和連接埠。圖 1 向您展示了在 WSDL 定義的什麼地方找到這些屬性的值。
圖 1:服務和端點映射。頂部:WSDL 檔案,底部:MXML 檔案
這些屬性是可選的。對於 service 屬性,它的值預設為第一個 <wsdl:service> 元素(首碼為 wsdl的 XML 標記表示屬於 WSDL 命名空間,並且用來構成一個 WSDL 檔案)的name屬性值。對於port 屬性,它的預設值是第一個包含在選定的 <wsdl:service> 元素中的 <wsdl:port> 元素的 name 屬性值。為了避免混亂,如果 WSDL 定義包括了多個 <wsdl:service> 和 <wsdl:port> 元素,最好明確設定這些屬性值。
從 WSDL 定義中選定了要使用的服務和連接埠後,為將要調用的每一個操作都添加一個 <mx:operation> 元素到 <mx:WebService> 元素中。每一個 <mx:operation> 元素的 name 屬性都會對應到 <wsdl:operation> 元素(它定義了 Web 服務調用)的 name 屬性。選中的 <wsdl:operation> 必須是 <wsdl:service> 和 <wsdl:port> 目標的一部分。 圖 2向您展示了在 WSDL 定義的什麼地方能定位name 屬性值。
圖 2:操作映射 頂部:WSDL 檔案,底部:MXML 檔案
<mx:operation> 元素還有其他一些屬性,它們的值不依賴於 WSDL 定義,但是也非常值得注意。其中 result和fault 屬性是 ActionScript 事件處理器。它們分別包含了 SOAP 響應和 SOAP 錯誤到達時要執行的 ActionScript 代碼。
請求映射
在選中 Web 服務操作後,Flex 的參數綁定機制被用來聲明這些操作的參數。正如下列代碼所示,每一個 <mx:operation> 元素都包含了一個 <mx:request> 元素,這個元素使用 ‘{}’ 包括了 XML 和 Flex 綁定的混合體。
<mx:WebService><mx:operation><mx:request><node1>{var1}</node1><node2>{var2}</node2></mx:request></mx:operation></mx:WebService>
|
一般來說,映射到 WSDL 或 Schema 的 XML 元素和 MXML 綁定引用到了 <mx:WebService> 元素範圍內的變數。
決定 <mx:request> 元素的內容是有一定困難的,因為這需要 WSDL 的 SOAP 綁定規則的知識。尤其是,基於不同的操作方式(document 或 RPC)和編碼機制(literal 或 encoded), <mx:request> 元素的內容會映射到不同的 WSDL 元素。
公用映射
面向文檔 - 文字
在 WSDL 定義的 SOAP 綁定部分決定了 SOAP 訊息體的結構,它再其中設定了使用的操作方式和編碼機制。操作方式是通過在 WSDL 定義綁定中的 <soap:operation> 元素(以 soap作為首碼的 XML 標記表示它屬於 SOAP 綁定命名空間,並且使用在 WSDL 定義中)的style屬性來指定的。它的值可以是document,表示面向文檔的操作,或者是rpc,表示 RPC 操作。在一個面向文檔的操作中,在 SOAP 體中交換的 XML 文檔不會有任何其他封裝元素。而且一個 RPC 式的操作中,SOAP 體被結構化來表示一個程序呼叫。它包含了一個根據操作命名的元素,而這個元素又按順序包含了一組根據巨集指令引數命名的元素及資料。表 2 舉例說明了這兩種方式產生的 SOAP 體的不同點。
表 2. 文檔及 RPC 方式之間的語義差別
| 文檔方式 |
RPC 方式 |
<soap:Body> <node1> <node2> <node3>data</node3> <node4>data</node4> </node2> <node5>data</node5> </node1>...</soap:Body>
|
|
<soap:Body> <operation_name> <parameter1>data</parameter1> <parameter2> <complex_element> <value1>data</value1> </complex_element> </parameter2>... </operation_name></soap:Body>
|
|
編碼機制是由綁定中的 <soap:body> 元素的 use屬性來決定的。它的值可以是literal,表示是一個 Literal/non-Encoded 訊息,或者是encoded,表示這個訊息是通過已定義好的一組編碼規則來生產。
下面的一組執行個體通過文檔-文字方式來使用一個帶 3 個操作的 Web 服務。在這些操作件不同點是它們的參數的數量和複雜度不一樣。圖 3、4、及5 舉例說明了 <mx:request> 元素的內容是怎樣映射到定義在這個 Web 服務的 WSDL 定義中的元素中。
圖 3:一個文檔-文字式的服務調用的一個巨集指令引數映射
圖 4:一個文檔-文字式的服務調用的多個巨集指令引數映射
圖 5:一個文檔-文字式的服務調用的一個複雜巨集指令引數映射
操作請求部分的 <wsdl:message> 元素包含了一個 <wsdl:part> 元素,並使用 element 屬性指向模式定義的元素。在文檔-文字式的操作請求中,part 指向的元素直接出現在 SOAP 體中,而沒有任何其他的封裝。因此, <mx:request> 元素的 XML 內容映射到 訊息部分指向的模式定義的元素。
面向 RPC - 文字
下面的執行個體使用了帶 3 個操作的 Web 服務,而且這三個操作的參數跟前面執行個體中的一樣,只是在 WSDL 中定義為了 RPC-文字式操作。因為這些原因, <wsdl:message> 元素包含了一個或多個 <wsdl:part> 子項目。每一個 <wsdl:part> 元素通過它的 type屬性的值來指向一個模式定義的類型。 圖6、7、及8 說明了在這種情況下 <mx:request> 元素的內容是怎樣映射到 WSDL 定義中的元素的。
圖 6: RPC-文字服務調用的單參數映射操作。
圖 7: RPC-文字服務調用的多參數映射操作。
圖 8:RPC-文字服務調用的複雜參數映射操作。
|
已測試的 Flex (Beta 3) 版本按 WSDL 定義的 <wsdl:message> 元素中的順序布置每一部分。它忽略連接埠類型定義中 >wsdl:operation> 元素的 parameterOrder 屬性裡設定的參數順序。 |
|
在一個面向 RPC 的請求中,SOAP 訊息體按順序包含一組元素,它們是按照 <wsdl:part> 元素進行命名的,所有這些元素又被一個按照每一個目標 <wsdl:part> 元素進行命名的元素所封裝。每一個按照 <wsdl:part> 命名的元素都屬於由 type 屬性指定的類型。結果,在 <mx:request> 元素中的頂級 XML 元素都映射為 <wsdl:part> 元素的名稱。每一個這些 XML 元素的內容都依賴於相關的 <wsdl:part> 元素的類型。如果是複雜模式類型, 8 所示,這些內容可以是其他映射到模式定義元素的 XML 元素。
面向 RPC - 編碼
在 RPC - 編碼操作調用中, <mx:request> 元素的內容映射到 WSDL 結構的方式跟前面 RPC-文字執行個體的一樣。唯一不同的一點是,SOAP 訊息體的內容包含一些額外的類型資訊,這是由編碼機制產生的。有一點要特別注意,WS-I Basic Profile 1.0 規範推薦中沒有包括使用編碼機制。它更要求使用 literal(非編碼式的)XML。
其他情況
這些執行個體中使用的 WSDL 定義是由 WebSphere Studio Application Developer V5.1 Web 服務嚮導自動生產的。因此,產生的 WSDL 定義的文檔結構遵守基於操作樣式值所表示的協定。 尤其是,對於 Document-style 操作,每一個 <wsdl:message> 元素包含一個 <wsdl:part> 元素,用來指向一個模式元素。對於 RPC 式的操作,每一個 <wsdl:message> 元素按順序包含一組 <wsdl:part> 元素,用來指向模式類型。在一個 Literal 訊息中,SOAP 體的內容依賴於 <wsdl:part> 是指向一個元素還是類型。表 3 列舉了可能的結合,並解釋了相應的訊息體(陰影單元代表了上面執行個體的情況)。
表 3. 當使用文字 XML 時可能的訊息部分定義和相應的訊息體
| 操作方式 |
Part 指向 |
SOAP Body |
| Document |
element |
part 指向的元素出現在訊息體內 |
| type |
part 指向的類型被用作訊息體的模式類型(不能處理多個 part) |
| RPC |
element |
part 指向的元素出現在根據 part 命名的封裝元素內 |
| Type |
part 指向的類型被用作根據 part 命名的封裝元素的模式類型。 |
結果映射
直到現在,我們都集中在定義調用一個 Web 服務操作所需要的 MXML 元素。現在我們討論一下怎樣處理從 Web 服務調用後接受到的結果。正如上面所提到的,Flex 把所有的 Web 服務調用都當作非同步處理,這意味著用戶端不會因為等待 Web 服務的響應而阻斷,而是繼續執行,而且一旦收到結果訊息就觸發一個事件。 <mx:operation> 標記的 result屬性指向在結果訊息一旦被接受後要執行的 ActionScript 代碼。Flex 將把 SOAP 響應還原序列化為 ActionScript 對象的一張圖。operation對象的result成員是對該圖的引用。結果對象的全限定名如下所示:
<value of WebService id>.<value of operation name>.result
|
ActionScript 中的點號(.)被用來更深層次地瀏覽結果對象,但這個需要您知道在響應 XML 中result對象代表了什麼。映射 Web 服務請求到 WSDL 檔案的規則,被相同地應用到了映射result 對象到 WSDL。
結束語
組織迅速採用包括 Web 服務在內的策略的轉移,對於充分掌握開發環境以建立使用這些環境的應用程式來說,是很有好處的。此外,既然 WSDL 一般來說是唯一的 Web 服務描述語言,為了開發整合了現有服務的應用程式,這可能是非常乏味而耗時的。Macromedia Flex 是一個 Rich Internet Application 平台,它完全定位於解決這些需求問題。通過利用大多數系統在 Web 服務上的巨大投資,設計人員和伺服器端開發人員一樣可以很容易地開發出互動可視化應用程式。我們已經示範了只需一點點 WSDL 定義結構的知識以及瞭解它們如何與 Flex 的 <mx:WebService> 聲明相關聯,就能快速地開發出強大而誘人的使用 Web 服務的應用程式,從而使快速開發使用 Web 服務的應用程式變成實實在在可以完成的需求。