當前位置:工程項目OA系統(tǒng) > 泛普各地 > 河北O(jiān)A系統(tǒng) > 石家莊OA系統(tǒng) > 石家莊OA信息化
使用WSDL部署Web服務,第2部分:簡單對象訪問協(xié)議(SOAP)
使用WSDL部署Web服務,第2部分:簡單對象訪問協(xié)議(SOAP)
--學習SOAP語法,用SOAP部署WSDL應用程序
Bilal Siddiqui (wap_monster@yahoo.com)
CEO, WAP
Monster
2002 年 3 月
簡單對象訪問協(xié)議(SOAP)提供對遠程對象的訪問。這些對象有的是簡單的 JavaBeans 組件或者是企業(yè) JavaBeans
組件和 COM/COM+ 對象等。這些對象駐留在不同企業(yè)內部并且可能存在于因特網的任何位置。因此,SOAP
通過因特網進行通信,它是一種在不同企業(yè)間交換信息的機制。在本文中,Bial 會詳細的討論 SOAP 通信,對象是怎樣用 SOAP 發(fā)布其功能的,怎樣調用
SOAP 對象,怎樣在有 SOAP 意識的應用程序間交換信息。他還會展示第 1 部分中提到的 WSDL 應用程序的 SOAP
服務部署,以及遠程服務器對它的調用。
SOAP 和 WSDL
我在本系列文章的第 1 部分介紹了
WSDL。WSDL 描述了 Web 服務的接口。Web 服務所有者將用 SOAP 來實現(xiàn)他們的接口。因此,WSDL 服務實際上作為 SOAP 服務一樣存在。一旦
Web 服務用戶擁有 WSDL 文件,他或者她就知曉接口的細節(jié)。他或者她就會用 SOAP 來與 Web 服務通信。
可以把 Web 服務考慮為對象,可以通過 WSDL 接口公開并且使用 SOAP 通過因特網遠程訪問。既然服務是對象,那么肯定有每種服務的相關屬性和每種服務調用的行為。SOAP 消息是 XML 文檔,可通過 HTTP 工作。
為什么用 SOAP?
B2B(Business-to-business)和
A2A(application-to-application )需求表明企業(yè)之間為交換信息而相互通信。這種概念被用在
B2B、工作流和跨企業(yè)集成中。例如,設想一條垂直供應鏈,在鏈上一家企業(yè)為了滿足它的客戶需求而需要調用其提供者的服務。而一些提供者需要沿供應鏈進一步下行來調用其它企業(yè)的服務。
很明顯,在此應用程序中互操作性是最為重要的。任何單個企業(yè)只能實現(xiàn) SOAP 通信通道的一端。另一端將是因特網上任何地方的實體。
在最近幾年里,企業(yè)之間的集成和互操作性已經成為軟件工程師和企業(yè)的一個挑戰(zhàn)性任務。平臺相關性也成為取得集成和互操作性的一個大問題。SOAP 依然是在企業(yè)間取得集成和互操作性最簡單的機制。
SOAP 體系結構
有了對 SOAP
和它的用途的基本理解,我現(xiàn)在就展開對其體系結構的討論以了解一些深層知識。請參閱圖 1,在此圖里面您可以識別典型 SOAP
通信體系結構中的一些組件:
SOAP 客戶機
SOAP 服務器
實際服務
圖 1. 一個典型 SOAP 通信體系結構的組件
讓我解釋上面所提到的每個實體的體系結構角色。
下面的討論參照圖 1。
SOAP 客戶機
SOAP 客戶機是一臺有 SOAP 機制的機器,它可以產生
SOAP 請求并通過 HTTP 發(fā)送到服務器。一條 SOAP 請求是一種類型的 SOAP 消息,通常只有兩種類型的 SOAP 消息:一條 SOAP 請求就是一臺
SOAP 客戶機發(fā)送給 SOAP 服務器的內容,一條 SOAP 響應就是 SOAP 服務器對 SOAP 客戶機響應的內容。清單 1 是典型的 SOAP
請求,請參閱清單 2 來回顧 SOAP 響應。
清單 1:一條簡單的 SOAP
請求
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" >
<SOAP-ENV:Body>
<m:getListOfModels xmlns:m = "uri reference"
>
</m:getListOfModels>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
SOAP 服務器
SOAP 服務器也是一臺有 SOAP 機制的機器,能夠接收來自
SOAP 客戶機的請求,并對之作出適當?shù)捻憫?。這些編過碼的響應會返回發(fā)出請求的 SOAP 客戶機。在 SOAP 服務器內部有三個實體:
服務管理器
被部署服務的列表
XML 轉換程序
服務管理器負責根據請求管理服務。請參閱清單 1 的服務請求,在這里元素 <m:getListOfModels xmlns:m="urn:MobilePhoneservice" > 包含了服務的名稱。服務管理器會讀取 SOAP 客戶機想調用的 SOAP 服務的名稱并檢查所需的服務實際上是否駐留于這臺 SOAP 服務器上。此后,它會查詢被部署服務的列表(SOAP 服務器所托管的所有服務的列表)。若存在,服務管理器將把 SOAP 請求傳送給 XML 轉換程序。XML 轉換程序就負責將 SOAP 請求的 XML 結構轉換成程序員用來實現(xiàn)實際服務的編程語言(例如,Java 編程語言)的結構。還要負責將來自實際服務的響應轉換回 SOAP 響應的 XML 結構。請參閱清單 2 獲得 SOAP 響應的說明。
清單 2:一條簡單的 SOAP
響應
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<m:getListOfModelsResponse
xmlns:m="urn:MobilePhoneservice">
<Model>M1</Model>
<Model>M2</Model>
<Model>M3</Model>
</m:getPriceResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
實際服務
圖 1 中標有 actual service
的框就是實際服務駐留的位置。服務實現(xiàn)可以是:例如,COM 組件或 JavaBeans 組件的形式。XML 轉換程序負責將 XML 結構轉換成合適的方法調用。當
XML 轉換程序調用了實際服務實現(xiàn)的某個方法時,這個方法就會完成它的工作并且將結果信息返回 XML 轉換程序。
請看一看圖 1 中連接 XML translator 和 actual service 的箭頭。箭頭的兩端同在一個企業(yè)內,這意味著同一個組織控制著通信兩端的接口。與穿過企業(yè)邊界的在 SOAP 客戶機和 SOAP 服務器之間的箭頭相比,這正是 SOAP 的目的所在。
SOAP 請求響應機制
當 SOAP 客戶機向 SOAP 服務器發(fā)送 SOAP
消息時,用 HTTP 協(xié)議傳輸。這就叫做 SOAP 與 HTTP 綁定。當 SOAP
服務器收到消息時,將消息交給服務管理器。服務管理器檢查被部署服務的列表,查找在 SOAP 消息中所需的服務。若沒有查找到所請求的服務,它將請求失敗返回給
SOAP 客戶機。但是若此項服務可以提供,控制權由服務管理器轉移給 XML
轉換程序(轉換程序完成合適語言的轉換并訪問實際服務實現(xiàn))。服務實現(xiàn)會處理請求并將結果返回給 XML 轉換程序。XML 轉換程序將結果轉換成 SOAP
客戶機能夠理解的 SOAP 響應(XML 文檔)。然后又一次用 HTTP 綁定來傳輸 SOAP 響應。
現(xiàn)在讓我們看一下 SOAP 與 HTTP
的綁定細節(jié)。
SOAP 與 HTTP 綁定
當您將 SOAP 和 HTTP 綁定在一起或在
HTTP 上操作 SOAP 時,您實際上將 HTTP 報頭加到了 SOAP 請求和響應上了。清單 1 是典型 SOAP 請求的結構,而清單 3、4、5 和 6
都是完整的 HTTP 請求,用來演示如何將 HTTP 報頭添加到清單 1 上。相似地,清單 7 是一條完整的 HTTP 響應,針對于來自清單 2 的 SOAP
響應。
無論您何時在 HTTP 上使用 SOAP,Content-Type 字段必須是 text/xml?,F(xiàn)在您可以察看清單 3 到清單 7 的詳情。
使用 HTTP 的 SOAP 請求
您可以將 SOAP 和 HTTP 的
POST 請求方法連用。為了發(fā)送一條 SOAP HTTP 請求,您需要在 HTTP 中提供一個 SOAPAction 報頭字段。
SOAPAction
指定了 SOAP 請求的目的。服務器(例如過濾 HTTP 中 SOAP 請求消息的防火墻)可以用字段 SOAPAction 的值來做決定。
HTTP 客戶機在發(fā)送一條 SOAP HTTP 請求時必須用此報頭字段。SOAPAction 可以有如下幾種值:
SOAPAction:"URI-Reference"
SOAPAction:"filename"
SOAPAction:""
SOAPAction:
清單 3:演示 SOAPAction 報頭字段中的 URI 引用
POST
/Vendors HTTP/1.1
Host: www.mobilephoneservice.com
Content-Type:"text/xml";Charset="utf-8"
Content-Length:
nnnn
SOAPACtion:"www.mobilephoneservice.com/Vendors/MobilePhoneservice#getListOfModels"
<?xml version="1.0"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
>
<SOAP-ENV:Body>
<m:getListOfModels
xmlns:m="urn:MobilePhoneservice"
>
</m:getListOfModels>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
清單 3 在 SOAPAction 中包括如下 URI 引用:www.mobilephoneservice.com/Vendors/MobilePhoneservice#getListOfModels
這個 SOAPAction 展示了兩部分內容。第一部分是一個特別 SOAP 部署的地址:www.mobilephoneservice.com/Vendors/MobilePhoneservice
第二部分是一個片段標識符,它給出了我們感興趣的方法的名字(#getListOfModels)。
清單 4:演示 SOAPAction 報頭字段中的一個文件名
POST
/Vendors HTTP/1.1
Host: www.mobilephoneservice.com
Content-Type:"text/xml";Charset="utf-8"
Content-Length:
nnnn
SOAPAction:"MobilePhoneservice#getListOfModels"
<?xml version="1.0"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
>
<SOAP-ENV:Body>
<m:getListOfModels
xmlns:m="urn:MobilePhoneservice"
>
</m:getListOfModels>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
清單 4 在 SOAPAction 中包含一個文件名(MobilePhoneservice#getListOfModels)。MobilePhoneservice 文件必須出現(xiàn)在主機 URI(www.mobilephoneservice.com/Vendors)中。這個主機 URI 是在 HTTP 報頭中 host 字段(www.mobilephoneservice.com)和文件夾名(/Vendors)的結合。
清單 5:演示 SOAPAction 報頭中的空字符串
POST
/Vendors HTTP/1.1
Host: www.mobilephoneservice.com
Content-Type:"text/xml";Charset="utf-8"
Content-Length:
nnnn
SOAPAction:""
<?xml version="1.0"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
>
<SOAP-ENV:Body>
<m:getListOfModels
xmlns:m="urn:MobilePhoneservice"
>
</m:getListOfModels>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
清單 5 在 SOAPAction 中包含一個空字符串("")。空字符串值表明 SOAP 的目的和 Host URI(www.mobilephoneservice.com/Vendors)的目的是一樣的。
清單 6:演示無值 SOAPAction 報頭
POST /Vendors
HTTP/1.1
Host: www.mobilephoneservice.com
Content-Type:"text/xml";Charset="utf-8"
Content-Length:
nnnn
SOAPAction:
<?xml version="1.0"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
>
<SOAP-ENV:Body>
<m:getListOfModels xmlns:m
="urn:MobilePhoneservice"
>
</m:getListOfModels>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
清單 6 沒有包含 SOAPAction 值。這表明沒有關于消息目的的信息。
用 HTTP 的 SOAP 響應
響應將可能是兩種類型的 SOAP
響應中的一種:
一個成功的 SOAP 操作產生 SOAP 結果
一個不成功的 SOAP 操作產生一條 SOAP 錯誤消息
清單 7:一條帶有 HTTP 報頭的成功 SOAP 響應
HTTP/1.1
Content-Type:"text/xml"; Charset="utf-8"
Content-Length: nnnn
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
>
<SOAP-ENV:Body>
<m:getListOfModelsResponse xmlns:m =
"URI-Reference">
<model>m1</model>
<model>m2</model>
</m:getListOfModels>
</SOAP-ENV:Body>
清單 7 是第一種情況,在此可以從 SOAP 服務器取得有意義的結果。
清單 8 是一條典型的 SOAP 錯誤消息。SOAP HTTP 響應遵循 HTTP 中通信狀態(tài)信息的 HTTP 狀態(tài)碼的語義。若在處理一條請求時發(fā)生一個 SOAP 錯誤,SOAP HTTP 服務器必須發(fā)出一條 HTTP 500 "Internal Server Error" 響應,同時在響應中包括一條帶有 SOAP 出錯元素的 SOAP 消息。
清單 8:一條帶有 HTTP 報頭的典型 SOAP 錯誤消息
HTTP/1.1
500 Internal Server Error
Content-Type: "text/xml";
Charset="utf-8"
Content-Length: nnnn
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultstring>Failed to process the
request</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
使用電子郵件的 SOAP
HTTP 不是唯一綁定 SOAP 消息的解決方案。若
HTTP 不合適,您可以用諸如 SMTP 的其它機制來用于 SOAP 綁定。將 SOAP 和 SMTP
綁定,您可以建立一條單向傳輸路由。兩條單向消息可以用來建立請求/響應通信。用 SMTP 來發(fā)送一條 SOAP 消息,您需要遵從以下步驟:
使用 MIME-Version 報頭字段
MIME-Version
用一個版本號來區(qū)別不同的 MIME 版本。它應用郵件處理代理(例如一個 POP 服務器)來區(qū)別舊版本和新版本所生成的郵件消息。請參閱清單 9,它使用了一個
MIME-Version 報頭字段。
清單 9:一個使用電子郵件的 SOAP 示例
TO:
<info@waxsys.com>
From: <abc@punjab.com>
Reply-To: <abc@punjab.com>
Date: SAT, 2 Feb 2002
16:00:00
Message-Id: <4FAB345C8D93E93B7A6E9@punjab.com>
MIME-Version: 1.0
Content-Type: text/xml;
charset=utf-8
Content-Transfer-Encoding: QUOTED-PRINTABLE
<?xml version ="1.0"
encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<prnt:echoString
xmlns:prnt="http://waxsys.com">
<msgString>Put
your mail
Message</msgString>
</prnt:echoString>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
使用 Content-Type 報頭字段:
Content-Type
用來標識消息主體中的數(shù)據類型。對于 SOAP 消息 Content-Type 應該有一個值“text/xml”。請參閱清單 9 ,它使用了
Content-Type。
使用 Content-Transfer-Encoding 字段:
Content-Transfer-Encoding 用來指定傳輸編碼的類型,也就是您所要傳輸?shù)臄?shù)據是字符格式還是二進制格式。清單 9 使用
Quoted-Printable 編碼,這種編碼符合依照 ASCII 字符集的可打印字符。這種對數(shù)據的編碼方式使郵件傳輸代理不可能修改結果八位元。請參閱清單
9,它使用了 Content-Transfer-Encoding 。
SOAP
模式與實現(xiàn)
SOAP 消息
一條 SOAP 消息只是一個 XML 文檔,由一個強制性的 SOAP Envelope
組成,SOAP Envelope 有一個可選的 SOAP Header 和一個必須有的 SOAP Body。
SOAP 模式的元素:
Envelope
Header
Body
Fault
Envelope:
Envelope 是表示一條 SOAP 消息的頂層元素。為了發(fā)送一條 SOAP
消息,必須包括此元素。Envelope 使用必要的 SOAP 名稱空間標識符(http://schemas.xmlsoap.org/soap/envelope/
)。若 Envelope 包含了錯誤的名稱空間,會產生一個關于 Envelope 名稱空間版本的錯誤。清單 10 是一個空 Envelope。稱其為“空
Envelope”是為了強調在通過“投遞”發(fā)出它之前,它最終應該包含一封“信”(也許是商業(yè)信)。SOAP 模式中的“信”就是指“SOAP Body”,HTTP
POST(在 HTTP 與 SOAP 的綁定一部分討論過)就是傳輸機制。
清單 10:一個空 SOAP
Envelope
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
</SOAP-ENV:Envelope>
Header:
SOAP Header 是可選的。您可以直接將 SOAP Body 放到 SOAP
Envelope 中并完全忽略報頭。報頭提供了一個擴展 SOAP 消息功能的機制。例如,認證就是由 SOAP Header
條目所提供的一種典型擴展。在此情況下,將有一個認證框架,它會使用 SOAP 作為更低級別的傳輸。請參閱清單 11 來查看在 SOAP 中的報頭實現(xiàn)。
清單 11:在一個 SOAP Envelope
中的報頭實現(xiàn)
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<m:Order
xmlns:m="some URI"
SOAP-ENV:mustUnderstand="1">
</m:Order>
</SOAP-ENV:Header>
</SOAP-ENV:Envelope>
Body:
Body
元素包含您實際要發(fā)送的消息。它是一個強制性的元素且其子元素通常屬于一個用戶定義的名稱空間。清單 12 展示了一條引用一個用戶定義的名稱空間“u”的 SOAP
消息。Body 元素是必要信息的容器。這個元素必須在 SOAP 消息中出現(xiàn)并且必須是 SOAP Envelope 元素的一個直接子元素。它也必須直接跟在
SOAP Header 元素的后面。若沒有 Header 元素,那么它應直接跟在 Envelope
元素的后面。主體可以包含子元素并且子元素可能是受限于名稱空間的。
清單 12: SOAP Envelope 內有 Header,還有
Body
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<m:Order
xmlns:m="some URI"
SOAP-ENV:mustUnderstand="1">
</m:Order>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<u:GetPrice
xmlns:u="some URI"
>
<model>m1</model>
</u:GetPrice>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Fault:
這個元素表明一條錯誤消息。它應作為一個主體條目出現(xiàn)并且不能在 Body
元素中出現(xiàn)一次以上。通常,F(xiàn)ault 元素會在一條 SOAP 響應消息中出現(xiàn),以表明在 SOAP 請求中出現(xiàn)錯誤。
Fault 的子元素:
faultcode(錯誤的標識)
faultstring(錯誤的描述)
faultactor(標識由誰導致的錯誤)
detail(錯誤細節(jié)。通常是一個應用程序特定錯誤,也就是說,它相當于在 SOAP
請求主體中用到地用戶定義的名稱空間)
清單 13 是一條典型的錯誤消息。
清單 13: 當應用程序出現(xiàn)錯誤時,SOAP Fault 的使用
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<m:Order
xmlns:m="some URI"
SOAP-ENV:mustUnderstand="1">
</m:Order>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring>Not
necessary
information</faultstring>
<detail>
<d:faultdetail
xmlns:d =
"uri-referrence">
<msg>
application
is not responding
properly.
</msg>
<errorcode>12</errorcode>
</d:faultdetail>
</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
來自第 1 部分的一條對 WSDL 文件的 SOAP 請求
已經解釋了 SOAP
消息(請求和響應)的常規(guī)語法,我將展示如何對本系列第 1 部分中的 MobilePhoneservice 開發(fā)一條 SOAP 請求。在第 1
部分中您設計一個完整的 WSDL 接口來解釋 MobilPhoneservice。移動公司在 MobilePhoneservice 中提供了兩種方法,一種是
getListOfModels(),另一種是 getPrice(modelNumber)。GetListOfModels()
沒有參數(shù)但是返回手機型號的一張列表,而 getPrice(modelNumber) 有一個參數(shù) modelNumber 并返回需求型號的 price。您將用
SOAP 請求格式對它作成文檔,但是首先讓我展示給您一般的 SOAP 請求和響應格式。
清單 14:SOAP 請求的一般格式
<SOAP-ENV:Envelope xmlns:SOAP-ENV ="SOAP schema's
URI"
<SOAP-ENV:Body>
<Instance:"Method Name"
xmlns:Instance= "URI where method is
located">
<parameter1>value</parameter1>
<parametern>value</parametern>
</Instance:"Method
Name">
</SOAP_Envelop:Body>
</SOAP-ENV:Envelope>
一條簡單的 SOAP 請求或響應只能表明一種服務的一個方法。包含一條 SOAP 請求的 Envelope 的一般格式遵從清單 14。將這種一般格式與清單 16 中的 getListOfModels() 的方法調用請求比較。在清單 16 中,我已經提供了方法和 URI 的名稱。既然在 getListOfModels() 中不需要參數(shù),所以 <m:getListOfModels> 在清單 16 中是一個空元素。
清單 15:一條 SOAP
響應的一般格式
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<Instance:"Method
Name"+"Response"
xmlns:Instance="URI where method is
located">
<return>
<responseparameter1>value</responseparameter1>
<responseparametern>value</responseparametern>
</return>
</Instance:
"Method
Name"+"Response">
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
清單 15 是一條一般的 SOAP 響應。Apache SOAP 服務器在方法名稱的后面增加了"Response"關鍵字并將返回值封入元素 <return> 中作為一個直接子方法元素。若返回值是復合型結構,那么 <return> 元素包含一個或多個 <item> 元素。將清單 15 與清單 17 相比,清單 17 是來自 getListOfModels() 的實際響應。清單 17 包含一系列項目,作為 Vector 數(shù)據類型,它是返回參數(shù)。相似地,清單 18 和 19 展示了針對 MobilePhoneservice 的方法 getPrice() 的 SOAP 請求和響應。
清單 16:調用 getListOfModels() 方法的 SOAP
請求
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<m:getListOfModels
xmlns:m = "www.mobilphoneservice.com"
>
</m:getListOfModels>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
清單 17:針對于來自清單 16 請求的 SOAP 響應
<?xml
version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:getListOfModelsResponse
xmlns:ns1="urn:MobilePhoneservice"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return
xmlns:ns2="http://xml.apache.org/xml-soap"
xsi:type="ns2:Vector">
<item
xsi:type="xsd:string">M1</item>
<item
xsi:type="xsd:string">M2</item>
<item
xsi:type="xsd:string">M3</item>
<item
xsi:type="xsd:string">M4</item>
<item
xsi:type="xsd:string">M5</item>
</return>
</ns1:getListOfModelsResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
清單 18:對于 getPrice 方法的 SOAP
請求
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<m:getPrice
xmlns:m ="www.mobilphoneservice.com">
<modelNumber xsi:type
="xsd:String">M1</modelNumber>
</m:getPrice>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
清單 19:對于來自清單 18 請求的 SOAP 響應
<?xml
version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:getPriceResponse
xmlns:ns1="urn:MobilePhoneservice"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return
xsi:type="xsd:string"> 5000
</return>
</ns1:getPriceResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
在 SOAP 服務器上部署基于 WSDL
的服務
在此部分您將在 Apache SOAP 服務器上部署來自第 1 部分的 WSDL 服務。Apache SOAP 工具箱將
WSDL 服務信息保存在一個部署描述符文件里面。部署描述符包含了 WSDL 服務的名稱和它擁有的所有方法。在運行時部署描述符會將這些名稱提供給 SOAP
服務器。同樣的部署描述符文件還包含了實現(xiàn)接口的 JavaBean 組件的地址。
清單 20:一個部署描述符的框架
<isd:service
xmlns:isd="http://xml.apache.org/xml-soap/deployment"
id="URN:SERVICE-URN">
<isd:provider
type="java"
scope="Request"
methods="EXPOSED-METHODS">
<isd:java
class="IMPLEMENTING-CLASS"/>
</isd:provider>
<isd:faultListener>org.apache.soap.server.DOMFaultListener
</isd:faultListener>
</isd:service>
清單 20 是一個部署描述符的框架,為了作為基于 WSDL 服務的部署描述符使用,它需要三項信息(URN:SERVICE-URN、EXPOSED-METHODS 和 IMPLEMENTING-CLASS)。URN:SERVICE-URN 是被部署服務的名稱。在此例中它是“urn:MobilePhoneservice”。EXPOSED-METHODS 是一個單空格分隔的由服務提供的方法的列表。在此部署中它是 getListOfModels getPrice。
IMPLEMENTING-CLASS 是帶有全路徑的 Java
類名稱。例如,samples.phonequote.MobilePhoneservice。在此例中測試應用程序時,您有如下目錄結構:
Apache SOAP 服務器:C:fooSOAP-2_2
Mobile phone
服務實現(xiàn):
C:fooSOAP-2_2samplesphonequoteMobilePhoneservice
因此,IMPLEMENTING-CLASS 路徑請參照您安裝 SOAP 工具箱的目錄。我沒有提供 Java 類的實際實現(xiàn)。它取決于業(yè)務邏輯并且可以是任何東西。
清單 21:MobilePhoneservice
的部署描述符
<isd:service
xmlns:isd="http://xml.apache.org/xml-soap/deployment"
id="urn:MobilePhoneservice">
<isd:provider
type="java"
scope="Request"
methods="getListOfModels
getPrice">
<isd:java
class="samples.phonequote.MobilePhoneservice"/>
</isd:provider>
<isd:faultListener>
org.apache.soap.server.DOMFaultListener
</isd:faultListener>
</isd:service>
清單 21 是來自第 1 部分對 WSDL 文件的完整部署描述符。
SOAP 客戶機與 SOAP
服務器的通信
我已經提供過一個應用程序樣本來演示一臺 SOAP 客戶機與一臺 SOAP
服務器的通信。為此我給過三個列表:Startup.html(清單 22)、Operation.html(清單 23)和 Execute.jsp(清單 24)。
StartUp.html(清單 22)是一個簡單的 HTML 文件,提供給用戶一個 GUI 并詢問他將要調用哪一個 SOAP 方法。用戶會選擇一個他需要的方法。
清單 22:一個作為前端的簡單 HTML
頁
<HTML>
<BODY
bgcolor="Teal">
<br/>
<p align="center">
<font
size="5" face="Arial" color="white"><b>
SOAP method
invocation demo </b></font>
</p>
<hr/>
<font
face="Arial" color="whitesmoke"
size="3">
<br/><b>
Click any of the method name to
execute.<br/>
1. Get the List of all Models that we
manufacture....
<a href="execute.jsp?index=1">
<font color="orange"> GetListOfModels
</font></a> <br/>
2. Get the Price of any particular
model......................
<a href="operation.html">
<font color="orange"> GetPrice
</font></a>
</b>
</BODY>
</HTML>
Operation.html(清單 23)將詢問客戶提供方法調用所需的參數(shù)。
清單 23:根據他或她所選擇的方法給予客戶一個
GUI
<HTML>
<BODY
bgcolor="Teal">
<br/>
<p align="center">
<font
size="5" face="Arial" color="white"><b>
GetPrice Operation
input Form </b>
</font></p>
<hr/>
<p
align="center">
<form action="execute.jsp"
method="POST">
<input type="hidden" name="index"
value="0">
<table
textColor="white">
<tr><td>
<font
color="whitesmoke"><b>Description
:</b></font>
</td><td><font
color="whitesmoke">
Method GetPrice is used to Get Price of given
Model
Number</font>
</td></tr>
<tr><td>
<font
color="whitesmoke"><b>Parameter(s)</b></font></td><td>
</td></tr>
<tr><td><font
color="whitesmoke">Model Number
</td></font>
<td><font
color="whitesmoke">
<input type="text" name="parameter"
size="30">
(required)
</font>
</td></tr>
<tr><td>
</td><td><input
type="Submit"
value="Invoke">
</td></tr>
</font>
</table>
</form>
</p>
</BODY>
</HTML>
Execute.jsp(清單 24)包含了所有的令人感興趣的代碼。它檢測所調用的方法和所傳遞的參數(shù)。然后發(fā)送給遠程服務器一個方法調用。
清單 24:檢測方法并發(fā)送給遠程服務器一個調用
<%@ page
language="java" import="java.util.Vector" %>
<%@ page
import="java.net.MalformedURLException, java.net.URL" %>
<%@ page
import="java.util.Vector" %>
<%@ page
import="org.apache.soap.SOAPException,
org.apache.soap.Constants" %>
<%@ page
import="org.apache.soap.rpc.Call, org.apache.soap.rpc.Response,
org.apache.soap.rpc.Parameter" %>
<%@ page
import="org.apache.soap.transport.http.SOAPHTTPConnection" %>
<%@ page
import="org.apache.soap.Fault" %>
<HTML>
<BODY
bgcolor="Teal">
<br/>
<p align="center">
<font
color="whitesmoke">
<%
boolean isParameter = false
;
SOAPHTTPConnection soapTransport = new
SOAPHTTPConnection();
// Address of the remote server.
// Normally
this should be dynamically passed and detected.
// We have hard coded
it only for demonstration.
URL url = new URL
("http://localhost:8080/soap/servlet/rpcrouter");
// Build the call.
Call call = new Call
();
call.setTargetObjectURI
("urn:MobilePhoneservice");
call.setSOAPTransport
(soapTransport);
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
// We'll detect which method user selected
// and
give a call accordingly.
// We'll pass parameters if
present.
if
(request.getParameter("parameter")!=null)
isParameter =
true;
if (request.getParameter("index").equals("0"))
{
call.setMethodName("getPrice");
Vector
params = new Vector();
String message = new String
(request.getParameter("parameter"));
params.addElement (new
Parameter("message", String.class,
message ,
null));
call.setParams(params);
}
else
call.setMethodName("getListOfModels");
Response resp = call.invoke ( url, /* actionURI */ ""
);
out.println("<p align=left>
<font size="4"
face="Arial" color="white">
Response of [
"+call.getMethodName()+"
]
</font><hr/>");
// Check the
response.
if (resp.generatedFault ()) {
Fault fault =
resp.getFault ();
out.println("<b>Fault is:</b>"+
fault.getFaultCode ()
+" ["+fault.getFaultString
()+"]");
} else {
Parameter result =
resp.getReturnValue ();
out.println("<b>Response is:
</b>"+ result.getValue
()+"");
}
%>
<font>
</p>
</BODY>
</HTML>
為了運行此應用程序,您需要兩臺 Apache SOAP 服務器。一臺服務器將用來與用戶通信并托管清單 22、23 和 24。另一臺服務器(也稱為遠程服務器)就是我們需要部署第 1 部分所講的基于 WSDL 服務的地方(在前一節(jié)描述,“在 SOAP 服務器上基于 WSDL 服務的部署”)。僅僅是為了演示,遠程服務器的地址 http://localhost:8080/soap/servlet/rpcrouter 已經硬編碼在 Execute.jsp(清單 24)中。在實際操作中您可以從 WSDL 文件中讀取它。
SOAP
中的簡單與復合數(shù)據類型
在此節(jié)中,我將從解釋簡單與復合數(shù)據類型的不同開始。然后展示如何在 SOAP 中對它們編碼。
簡單類型包括字符串、浮點數(shù)、整數(shù)、枚舉等。例如一部手機的“name”的數(shù)據類型就是“string”。復合類型由簡單類型組成但只代表一個實體。例如,“Student”類型記錄可以有不同的屬性,如“studentName”屬于類型“string”,“studentRollNumber”屬于類型“int”但都只代表一個實體“Student”。
清單 25 包含了一個名稱為“Mobile”的復合數(shù)據類型。您會在后面的 SOAP 請求中用到。
清單 25: “Mobile”類型的模式定義結構
1<? xml
version="1.0" ?>
2<xsd:schema
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
3
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
4
targetNameSpace= "www.mobilephoneservice.com/phonequote">
5
<xsd:element name ="Mobile">
6 <xsd:complexType>
7
<xsd:element name="modelNumber" type="xsd:int">
8
<xsd:element name="modelName" type="xsd:string">
9
<xsd:element name="modelWeight" type="xsd:int">
10
<xsd:element name="modelSize" type="xsd:int">
11
<xsd:element name="modelColor">
12 <simpleType
base="xsd:string">
13 <enumeration value="white"
/>
14 <enumeration value="blue" />
15
<enumeration value="black" />
16
<enumeration value="red" />
17 <enumeration
value="pink" />
18 </simpleType>
19
</xsd:element>
20 </complexType>
21
</xsd:element>
22</xsd:schema>
在清單 25 中的第 5 行展示了我們的類型名稱(Mobile),而第 6 行說明它是復合數(shù)據類型。因復合數(shù)據類型有屬性,所以在第 7 行到第 12 行展示了定義為子元素的“Mobile”數(shù)據類型的屬性。
第 7 行聲明的元素展示了“Mobile”類型有一個名稱為“modelNumber”的屬性且其類型為“int”(也就是說,“modelNumber”只能采用整數(shù)值)。類似的,第 9 行和第 10 行聲明的元素具有同樣的類型但有不同的屬性名稱。在第 8 行定義的元素具有名稱為“modelName”的屬性且其類型是“string”。
第 11 行的元素因有位于第 12 行的、名稱為“simpleType”的子元素,所以需要更好的理解。這里您在復合類型 Mobile 中定義了一個簡單類型。simpleType 的名稱為“modelColor”且它的類型是“enumeration”。它有一個屬性“base”具有的值為 "xsd:string",這表明簡單類型“modelColor”具有在 SOAP 模式中定義的類型“string”的功能。在第 13 行到第 17 行中的每一個 <enumeration> 標記都具有一個屬性:“value”("white" "blue"、 "black"、 "red" 和 "pink")。枚舉類型使我們能夠從多項選項中選擇一個值。
在 SOAP 請求中使用復合數(shù)據類型
清單 26 演示了在 SOAP
請求中復合類型的使用。它展示了一個在 Body 元素中的攜帶請求的 Envelope,在 Body 元素中,您正調用“m”名稱空間的 addModel
方法。清單 26 使用數(shù)據類型“Mobile”,此數(shù)據類型在清單 25 中定義。
AddModel 方法攜帶一個類型為“Mobile”的參數(shù)。我們以“msd”名稱空間引用來引用“Mobile”結構。請參閱清單 26 的 <SOAP-ENV:Envelope> 元素中的 "xmlns:msd" 聲明。這是一個在 SOAP 請求中使用用戶定義數(shù)據類型的示例。
清單 26:實現(xiàn)在清單 25 中定義的“Mobile”結構
1
<SoAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
2
xmlns:xsd="http://www.w3.org/1999/XMLSchema"
3 xmlns:msd="www.mobilephoneservice.com/phonequote">
4
<SOAP-ENV:Body>
5 <m:addModel xmlns:m="www.mobilephoneservice.com">
6
<msd:Mobile>
7
<modelNumber>1</modelNumber>
8
<modelName>mlr97</modelName>
9
<modelWeight>10</modelWeight>
10
<modelSize>4</modelSize>
11
<modelColor>white</modelColor>
12
</msd:Mobile>
13 </m:addModel>
14
</SOAP-ENV:Body>
15<SOAP-ENV:Envelope>
總結
在這一部分中,您已經學習了
SOAP 語法、請求、響應、HTTP 綁定和使用電子郵件的 SOAP 使用。您也了解了服務于 Apache SOAP 客戶機的 Apache SOAP
服務器。最后,我簡述了用戶定義數(shù)據類型的主題,它是一個需要我們仔細學習的高級主題。在此系列文章的下一部分,您會學習更多的用戶定義數(shù)據類型示例。我還會檢驗
SOAP 的互操作性(也就是說,怎樣使來自不同供應商的 SOAP 實現(xiàn)相互協(xié)調)。
參考資料
- 請單擊在此文章頂部或底部的討論來參加關于此文章的討論論壇。
- 簡單對象訪問協(xié)議(SOAP)
1.1 是 W3C SOAP 的正式規(guī)范。
- 此系列文章的第 1 部分:用
WSDL 部署 Web 服務。
- 一篇有趣的 XML.Com 上的 SOAP 文章。
- 一篇對 SOAP 基礎知識的介紹。
- Scribner, Kenn 等的“Understanding SOAP” ,Sams。
- Bequet, Henry 的“Professional Java SOAP”,Wrox。
- 自 Apache's Web 站點下載本文所用到的 Apache SOAP 工具箱。
關于作者
Bilal Siddiqui 是一位 XML
顧問。自 1995 年畢業(yè)于 Lahore 工程技術大學電子工程專業(yè)后,他開始為工業(yè)控制系統(tǒng)設計軟件解決方案。后來他轉到了 XML 并用自己 C++
的編程經驗來構建基于 Web 和 WAP 的 XML 處理工具、服務器端的解析解決方案和服務應用程序。您可以通過 wap_monster@yahoo.com 發(fā)電子郵件給 Bilal
來索取本文中包含的代碼文件的拷貝。
瀏覽:使用WSDL部署Web服務,第1部分:Web服務和WSDL簡介
- 1Web服務內幕,第5部分:進入流--用WSFL建模的商業(yè)流程
- 2Web服務設計師,第3部分:Web服務是CORBA的翻版嗎?
- 3石家莊OA信息化的基本XML和RDF技術(二):將文件合并到RDF模型和基本的RDF查詢
- 4Providing Content Through Web Services
- 5微軟、IBM和BEA聯(lián)合發(fā)表Web服務新標準
- 6泛普OA個性化門戶主要提供了基于用戶的門戶個性化流程
- 7Web服務設計師,第6部分:基于付費的Web服務的催化劑
- 8石家莊OA信息化的價值和挑戰(zhàn)
- 9石家莊OA信息化還得管知識過程(by AMT 夏敬華)
- 10SOAP技術與B2B應用集成--SOAP的消息結構與數(shù)據的組織方法
- 11管理結構性的、半結構性的以及非結構性的數(shù)據類型(by AMT 邢華編譯)
- 12微軟展示新版互聯(lián)網服務MSN 8.0
- 13利用辦公自動化系統(tǒng)進行石家莊OA信息化
- 14在Web Service中使用ASP.net狀態(tài)保持
- 15為網絡用戶頒發(fā)“護照” 微軟又意欲何為?
- 16源天軟件獲2008年度中國IT服務創(chuàng)新獎
- 17Building a Stock-Quotes Web Service
- 18炎黃盈動AWS石家莊OA信息化應用套件
- 19Web服務:WS-Inspection 1.0
- 20Sun拒入“WS-I” 不想跟微軟IBM玩游戲
- 21石家莊OA信息化與知識價值鏈(BY AMT 夏敬華)
- 22Managing Knowledge Workers
- 23如何畫石家莊OA信息化項目實施方法論這幅地圖(by AMT夏敬華孔祥云)
- 24中小企業(yè)如何化解經濟危機
- 25石家莊OA信息化方面的站點資源!
- 26網絡、知識增長和經濟發(fā)展
- 27在ASP程序中調用Web Service
- 28Web Service 的異步調用
- 29XML Web Service 安全性
- 30Web服務設計師,第2部分:動態(tài)電子商務模式
成都公司:成都市成華區(qū)建設南路160號1層9號
重慶公司:重慶市江北區(qū)紅旗河溝華創(chuàng)商務大廈18樓