免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
了解 Web 服務(wù)規(guī)范,第 1 部分: SOAP

2006 年 9 月 11 日

面向服務(wù)的體系結(jié)構(gòu)(Service-Oriented Architectures,SOA)當(dāng)前強(qiáng)調(diào)的重點(diǎn)在 Web 服務(wù)上,但很容易被所傳播的各種信息搞得昏頭轉(zhuǎn)向。本系列教程將對(duì)主要 Web 服務(wù)規(guī)范進(jìn)行全面說(shuō)明,從簡(jiǎn)單對(duì)象訪問(wèn)協(xié)議(Simple Object Access Protocol,SOAP)一直介紹到 WS Business Process Execution Language (WS-BPEL)。本教程將介紹 Web 服務(wù)和 SOAP 基本概念,并說(shuō)明如何構(gòu)建 SOAP 服務(wù)器和客戶(hù)機(jī)。

開(kāi)始之前

本系列教程將說(shuō)明構(gòu)建一家假想的報(bào)社 Daily Moon 的基于 Web 訪問(wèn)的工作流系統(tǒng)的詳細(xì)步驟。主要針對(duì)的是希望了解有關(guān) Web 服務(wù)的更多信息的開(kāi)發(fā)人員,以便他們能更為高效地創(chuàng)建應(yīng)用程序。非技術(shù)用戶(hù)也可以從中獲得一些好處,因?yàn)樵谟懻撊绾尉幊糖皩?duì)相關(guān)概念進(jìn)行了解釋。

您應(yīng)該具有基本編程知識(shí),如果希望按照實(shí)際編程示例進(jìn)行操作,還需要一定的 Java 知識(shí)。我們將討論 XML(但沒(méi)有必要對(duì)其進(jìn)行深入討論),并將涵蓋任何必要的概念。

關(guān)于本系列

本系列教程以假想的報(bào)社 Daily Moon 為例,為了提高在競(jìng)爭(zhēng)激烈的環(huán)境中的生產(chǎn)力,其員工將使用各種 Web 服務(wù)來(lái)創(chuàng)建工作流系統(tǒng),我們將在此過(guò)程中講述各個(gè) Web 服務(wù)基本概念。

第 1 部分比較簡(jiǎn)單,將說(shuō)明 Web 服務(wù)背后的基本概念,并演示如何使用 SOAP(以后要討論的大部分內(nèi)容的基礎(chǔ)規(guī)范)來(lái)將 Classifieds Department 連接到內(nèi)容管理系統(tǒng)。

本系列以后的部分將以這些基本概念為基礎(chǔ):

  • 第 2 部分進(jìn)一步深入說(shuō)明如何使用 Web 服務(wù)描述語(yǔ)言(Web Services Description Language,WSDL)定義 Web 服務(wù)預(yù)期產(chǎn)生的消息,從而使團(tuán)隊(duì)更方便地創(chuàng)建服務(wù)以及連接到服務(wù)的客戶(hù)機(jī)。
  • 在第 3 部分中,團(tuán)隊(duì)希望準(zhǔn)備一系列服務(wù),并希望能方便地查找這些服務(wù)。與此對(duì)應(yīng),統(tǒng)一描述、發(fā)現(xiàn)和集成(Universal Description, Discovery and Integration,UDDI)提供了可用服務(wù)的可搜索注冊(cè)中心,以便將自己的服務(wù)發(fā)布給其他人。
  • 第 4 部分和第 5 部分討論 WS-Security 和 WS-Policy,將詳細(xì)說(shuō)明如何保證該報(bào)社的服務(wù)的安全,以及團(tuán)隊(duì)為了訪問(wèn)這些剛提供了安全保護(hù)的服務(wù)需要進(jìn)行哪些更改。
  • 第 6 部分重點(diǎn)討論的是互操作性,因?yàn)楸仨殢膯蝹€(gè)系統(tǒng)訪問(wèn)來(lái)自幾個(gè)不同實(shí)現(xiàn)的服務(wù)。第 6 部分討論了在 WS-I 證書(shū)中涉及的要求和測(cè)試。
  • 最后,第 7 部分演示了如何使用業(yè)務(wù)流程執(zhí)行語(yǔ)言(Business Process Execution Language,WS-BPEL)來(lái)從各個(gè)服務(wù)創(chuàng)建復(fù)雜應(yīng)用程序。

接下來(lái)讓我們更為詳細(xì)了解一下本教程中將討論的內(nèi)容。





回頁(yè)首


關(guān)于本教程

本教程將向您以及假想的 Daily Moon Classifieds Department 介紹 Web 服務(wù)的概念。您將了解該團(tuán)隊(duì)如何與現(xiàn)有 Web 服務(wù)系統(tǒng)集成以及如何創(chuàng)建服務(wù)的詳細(xì)過(guò)程。重點(diǎn)將是簡(jiǎn)單對(duì)象訪問(wèn)協(xié)議 (SOAP)。

在本教程中,您將了解以下內(nèi)容:

  • Web 服務(wù)的基本概念
  • XML 的基本知識(shí)
  • SOAP 消息的結(jié)構(gòu)和用途
  • 如何安裝應(yīng)用服務(wù)器以在其上運(yùn)行 Web 服務(wù)應(yīng)用程序。
  • 如何將 Web 服務(wù)實(shí)現(xiàn)安裝到應(yīng)用服務(wù)器中
  • 如何以編程方式創(chuàng)建 SOAP 消息。
  • 如果使用 Java 和 Apache Axis2 為基于 SOAP 的 Web 服務(wù)創(chuàng)建客戶(hù)機(jī)
  • 如何使用 Java 和 Apache Axis2 創(chuàng)建基于 SOAP 的 Web 服務(wù)

在本教程中,Classifieds Department 將通過(guò)創(chuàng)建客戶(hù)機(jī)來(lái)與內(nèi)容管理系統(tǒng)集成。您還將了解該部門(mén)與之交互的一個(gè)服務(wù)的創(chuàng)建過(guò)程。編程示例采用 Java 語(yǔ)言,并使用了 Apache Axis2 項(xiàng)目,但其中的概念幾乎適用于任何語(yǔ)言和環(huán)境。





回頁(yè)首


先決條件

為了按照本教程所示的處理代碼,您需要有以下軟件:

  • Apache Geronimo 或其他應(yīng)用服務(wù)器。您將在本教程中創(chuàng)建各種 Web 服務(wù),需要在其上運(yùn)行這些服務(wù)的應(yīng)用程序。當(dāng)然,由于 Web 服務(wù)應(yīng)當(dāng)可互操作,因此使用何種應(yīng)用服務(wù)器并不重要。在本教程中,我們將演示如何安裝和使用 Apache Geronimo(IBM? WebSphere? Community Edition 也是構(gòu)建于其上的)。還可以使用 WebSphere Application Server 等其他應(yīng)用服務(wù)器??梢詮?Apache Geronimo Downloads 站點(diǎn)下載 Apache Geronimo。
  • Apache Axis2 或其他 SOAP 實(shí)現(xiàn)??梢允謩?dòng)創(chuàng)建 SOAP 消息,也可以手動(dòng)對(duì)其進(jìn)行解釋?zhuān)诌吶绻幸粋€(gè)可用實(shí)現(xiàn)就會(huì)方便得多。您將使用的是 Apache Axis2,其中包含了各種 SOAP 相關(guān)的 API,可極大地簡(jiǎn)化您的工作??梢栽谝韵戮W(wǎng)址下載 Apache Axis2:Apache.org。本教程使用的是 0.94 版,但應(yīng)該也能使用更高版本。
  • Java? 2 Standard Edition 1.4 或更高版本。這兩個(gè)工具都基于 Java,和將在本教程中構(gòu)建的服務(wù)和客戶(hù)機(jī)一樣??梢詮?a >此處下載 J2SE SDK。
  • 另外,還需要 Web 瀏覽器和文本編輯器,但我想您已經(jīng)有了這兩個(gè)工具。如果愿意,還可以使用 Eclipse 之類(lèi)的 IDE,但由于本教程的重點(diǎn)是技術(shù)而不是工具,因此我將使用文本編輯器和命令行來(lái)編輯和編譯文件。

什么是 Web 服務(wù)?

首先,讓我們從總體上了解一下什么是 Web 服務(wù),以及它們?yōu)楹螌?duì)軟件開(kāi)發(fā)重要。

究竟為什么重要呢?

如果您沒(méi)有聽(tīng)說(shuō)過(guò)有關(guān)面向服務(wù)的體系結(jié)構(gòu) (SOA) 和 Web 服務(wù)的大量信息,您就不會(huì)閱讀本文,那么問(wèn)題就應(yīng)該是,為什么此內(nèi)容這樣重要?答案是,此內(nèi)容之所以重要,是因?yàn)檫@是應(yīng)用程序彼此進(jìn)行通信的方式的典型變化。SOAs 已經(jīng)存在很長(zhǎng)很長(zhǎng)時(shí)間了。SOA 最初主要由中間件應(yīng)用程序組成,至少進(jìn)行連接的兩端都屬于同一種類(lèi)型的中間件。另一方面,Web 服務(wù)由一組標(biāo)準(zhǔn)組成,用于在不需要特定類(lèi)型的中間件、編程語(yǔ)言甚至操作系統(tǒng)的前提下讓各種不同的系統(tǒng)進(jìn)行通信。接下來(lái),讓我們了解一下其發(fā)展的歷程。





回頁(yè)首


傳統(tǒng)應(yīng)用程序

首先從計(jì)算機(jī)發(fā)明開(kāi)始,當(dāng)時(shí)給人感覺(jué)非常不錯(cuò)。計(jì)算機(jī)能執(zhí)行奇跡般的任務(wù),可實(shí)現(xiàn)很多手動(dòng)工作的自動(dòng)化,包括復(fù)雜的計(jì)算、財(cái)務(wù)工作等等很多其他任務(wù)。

但傳統(tǒng)應(yīng)用程序是“豎井”(Silo) 型的。人力資源應(yīng)用程序無(wú)法與財(cái)務(wù)應(yīng)用程序真正通信,而后者又無(wú)法和分布應(yīng)用程序進(jìn)行真正的通信。所有這些應(yīng)用程序都有獨(dú)立的領(lǐng)域,在獨(dú)立的計(jì)算機(jī)上運(yùn)行,盡管很有用,但并不能很好地在彼此間共享數(shù)據(jù)。當(dāng)時(shí)可以選擇對(duì)批處理流程進(jìn)行連接,以將數(shù)據(jù)從一個(gè)系統(tǒng)移動(dòng)到另一個(gè)系統(tǒng),但這并不適合進(jìn)行實(shí)時(shí)集成。





回頁(yè)首


分布式計(jì)算

在我們的進(jìn)化鏈中的第二步是分布式計(jì)算。分布式計(jì)算允許不同的應(yīng)用程序彼此進(jìn)行通信(即使位于不同的計(jì)算機(jī)上也是如此)。CORBA、MTS 和 Enterprise Java Bean (EJB) 等技術(shù)提供了包含各種類(lèi)別的注冊(cè)中心的系統(tǒng),因此應(yīng)用程序可以找到其希望與之進(jìn)行交互的組件,然后像調(diào)用本地的組件一樣調(diào)用這些組件。

這些系統(tǒng)由可同時(shí)滿(mǎn)足這兩個(gè)要求的中間件(或更具體一些,面向消息的中間件)提供支持?,F(xiàn)在能以特定的方式構(gòu)建應(yīng)用程序,即使位于不同的地理位置,也能訪問(wèn)其他系統(tǒng)上的資源。

但仍然有一個(gè)問(wèn)題。雖然系統(tǒng)可以自由地與系統(tǒng)內(nèi)的任何對(duì)象進(jìn)行通信,但仍然是一個(gè)封閉的系統(tǒng)。至少,客戶(hù)機(jī)應(yīng)用程序必須與服務(wù)器應(yīng)用程序使用相同的技術(shù)。另外,通常并不會(huì)將系統(tǒng)設(shè)計(jì)為從創(chuàng)建其的個(gè)體組織外進(jìn)行訪問(wèn)。





回頁(yè)首


Web 服務(wù)

此進(jìn)化鏈中下一個(gè)幾乎不可避免的鏈接點(diǎn)就是 Web 服務(wù)?!癢eb 服務(wù)”基于 XML 和 HTTP(大多數(shù)情況下),對(duì)很多人具有不同的含義,但在此處,我們要將 Web 服務(wù)作為系統(tǒng)間基于 SOAP 的消息交換進(jìn)行討論。

這些消息由 XML 組成(XML 是一個(gè)基于文本的開(kāi)放標(biāo)準(zhǔn)),可由來(lái)自任何應(yīng)用程序(任何設(shè)計(jì)為接收此類(lèi)消息的應(yīng)用程序)的任何人進(jìn)行訪問(wèn)。這就擴(kuò)展了應(yīng)用程序的范圍,從而包含任何可通過(guò)網(wǎng)絡(luò)對(duì)其進(jìn)行訪問(wèn)的任何人。(如果這讓您開(kāi)始考慮安全問(wèn)題,不要緊,您將在本系列的第 4 部分了解如何處理這方面的問(wèn)題。)

基于 SOAP 的 Web 服務(wù)將要發(fā)送與清單 1 中所示類(lèi)似的 XML 消息。


清單 1. 基于 SOAP 的 Web 服務(wù)

            <SOAPenv:Envelope
            xmlns:SOAPenv="http://schemas.xmlSOAP.org/SOAP/envelope/"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <SOAPenv:Body>
            <req:getNumberOfArticles xmlns:req="http://daily-moon.com/CMS/">
            <req:category>classifieds</req:category>
            </req:getNumberOfArticles>
            </SOAPenv:Body>
            </SOAPenv:Envelope>
            

這些消息將從一個(gè)系統(tǒng)進(jìn)入另一個(gè)系統(tǒng)(通常通過(guò) HTTP)。接收系統(tǒng)對(duì)消息進(jìn)行解釋?zhuān)M(jìn)行應(yīng)該進(jìn)行從處理,然后發(fā)送另一個(gè) SOAP 消息作為響應(yīng)。

這個(gè)系統(tǒng)很簡(jiǎn)單,正因?yàn)槿绱?,有很多企業(yè)級(jí)計(jì)算方面的內(nèi)容都尚未涉及。幸運(yùn)的是,其中的很多方面已被納入考慮范疇,且具有自己的相關(guān)規(guī)范來(lái)確定此事務(wù)應(yīng)如何進(jìn)行,以包含傳統(tǒng)的面向消息的中間件的很多安全和其他方面的內(nèi)容。





回頁(yè)首


其他類(lèi)型的 Web 服務(wù)

如果我沒(méi)有說(shuō)明 SOAP 并不是唯一的處理 Web 服務(wù)的方法,那就有些失職了。有很多其他基于 XML 的方法用于在系統(tǒng)間發(fā)送信息,其中一些適用于企業(yè)環(huán)境,而另一些則不適合此用途。例如,Amazon 是為公眾提供對(duì)其系統(tǒng)的 Web 服務(wù)訪問(wèn)的第一批基于 Web 服務(wù)的公司之一。Amazon 包含了一個(gè)基于 SOAP 的服務(wù),但也提供了一個(gè)基于 Representational State Transfer (REST) 的服務(wù)。

REST 是一種 Web 服務(wù)類(lèi)型,其中,用戶(hù)直接訪問(wèn) URL,相應(yīng)的響應(yīng)是與清單 2 中所示類(lèi)似的簡(jiǎn)單 XML 文檔。


清單 2. REST 響應(yīng)

            <currentArticles>
            <category>classifieds</category>
            <subcategory>forsale</subcategory>
            <article id="888204">
            <articleHeadline></articleHeadline>
            <articleText>30 ft ladder, only used once.  Willing to let
            go for half it‘s worth. Has slight dent near the middle.
            Harder than a human head. $150 OBO.</articleText>
            </article>
            <article id="888242">
            <articleHeadline></articleHeadline>
            <articleText>Vintage 1963 T-Bird.  Less than 300 miles.
            Driven by my daughter until I took it away.  Serious inquires only.
            555-3264 after 7 PM.</articleText>
            </article>
            </currentArticles>
            

這些消息并沒(méi)有特定的格式。可以為任何數(shù)據(jù)。

另一種 Web 服務(wù)類(lèi)型要使用 XML-RPC 之類(lèi)的標(biāo)準(zhǔn)。在這種情況下,命令將通過(guò)與清單 3 中所示類(lèi)似的 XML 發(fā)送到系統(tǒng)。


清單 3. XML-RPC

            <?xml version="1.0"?>
            <methodCall>
            <methodName>CMS.getNumberOfArticles</methodName>
            <params>
            <param>
            <value><string>classifieds</string></value>
            </param>
            <param>
            <value><string>forsale</string></value>
            </param>
            </params>
            </methodCall>
            

其響應(yīng)將采用類(lèi)似的格式。

在學(xué)習(xí)使用 SOAP 的過(guò)程中,您可以會(huì)打心底里認(rèn)為 REST 和 XML-RPC 比基于 SOAP 的系統(tǒng)要簡(jiǎn)單得多。的確如此。在某些情況下 REST 和 XML-RPC 比 SOAP 系統(tǒng)簡(jiǎn)單。不過(guò),我們討論的不是在網(wǎng)站上顯示天氣的簡(jiǎn)單應(yīng)用程序。我們此處討論的是企業(yè)級(jí)應(yīng)用程序,而企業(yè)級(jí)的應(yīng)用程序需要企業(yè)級(jí)的屬性,如安全、互操作性等等。這些功能在有關(guān)基于 SOAP 的 Web 服務(wù)的其他規(guī)范中進(jìn)行了定義,因而,從長(zhǎng)期來(lái)看,SOAP 更適合用于企業(yè)級(jí)應(yīng)用程序。

讓我們了解一下這些規(guī)范。





回頁(yè)首


基本 Web 服務(wù)規(guī)范

Web 服務(wù)規(guī)范通常歸為兩類(lèi):基本 Web 服務(wù)規(guī)范和擴(kuò)展 Web 服務(wù)規(guī)范?;疽?guī)范有:

  • SOAP:SOAP 規(guī)范是所有基于 SOAP 的 Web 服務(wù)的基礎(chǔ),詳細(xì)說(shuō)明了實(shí)際消息的格式。其中還詳細(xì)說(shuō)明了應(yīng)用程序應(yīng)如何對(duì)待消息的特定方面(如“Header”中的元素),從而可以創(chuàng)建特定類(lèi)型的應(yīng)用程序,使其中的消息在達(dá)到最終的目的地前在多個(gè)中間層之間進(jìn)行傳遞。本教程將涵蓋 SOAP 規(guī)范的內(nèi)容。
  • WDSL:Web 服務(wù)描述語(yǔ)言是詳細(xì)說(shuō)明描述基于 SOAP 的 Web 服務(wù)的標(biāo)準(zhǔn)方式的規(guī)范,包括消息應(yīng)采用的形式以及應(yīng)將其發(fā)送到何處。其中還詳細(xì)說(shuō)明了此類(lèi)消息的響應(yīng)。當(dāng)與相應(yīng)的工具結(jié)合使用時(shí),WSDL 允許以編程方式創(chuàng)建對(duì) Web 服務(wù)的調(diào)用,甚至不用知道所查找的 Web 服務(wù)是什么;應(yīng)用程序可以從 WSDL 文件中提取這些詳細(xì)信息,并提供要使用的編程接口。我們將在本系列的第 2 部分討論 WSDL。
  • UDDI:統(tǒng)一描述、發(fā)現(xiàn)和集成 (Universal Description, Discovery and Integration) 是一項(xiàng)從最初提出后發(fā)生了一系列變化的標(biāo)準(zhǔn)。其最初的目的是為了給各個(gè)公司提供在全球注冊(cè)中心中注冊(cè)服務(wù)并在此注冊(cè)中心中搜索可能想使用的服務(wù)的機(jī)制。不過(guò),由于很多公司對(duì)于將其系統(tǒng)對(duì)外開(kāi)放的問(wèn)題上都相當(dāng)保守,這個(gè)目標(biāo)并沒(méi)有完全實(shí)現(xiàn)。但是,很多公司已將 UDDI 作為內(nèi)部的服務(wù)及服務(wù)信息注冊(cè)中心使用,本系列第 3 部分將對(duì)其使用進(jìn)行詳細(xì)論述。

以上是一些基礎(chǔ)知識(shí)。另外差不多還有數(shù)十種擴(kuò)展標(biāo)準(zhǔn),可進(jìn)一步擴(kuò)展基于 SOAP 的服務(wù)的用途。





回頁(yè)首


擴(kuò)展 Web 服務(wù)規(guī)范

總共有數(shù)十種 WS-* 規(guī)范,其中幾種對(duì)企業(yè)尤為有用。即:

  • WS-Security:此規(guī)范處理加密和數(shù)字簽名,允許創(chuàng)建特定類(lèi)型的應(yīng)用程序,以防止竊聽(tīng)消息,且能實(shí)現(xiàn)不可否認(rèn)功能。本系列的第 4 部分將討論 WS-Security。
  • WS-Policy:此規(guī)范對(duì) WS-Security 進(jìn)行了擴(kuò)展,允許更具體地說(shuō)明誰(shuí)可以采用何種方式使用服務(wù)。本系列的第 5 部分將討論 WS-Policy。
  • WS-I:盡管 Web 服務(wù)應(yīng)設(shè)計(jì)成具有互操作性,但在實(shí)際中,各個(gè)規(guī)范對(duì)不同實(shí)現(xiàn)的解釋的靈活性常常足以導(dǎo)致出現(xiàn)問(wèn)題。WS-I 提供了一組可用于防止出現(xiàn)各種問(wèn)題的標(biāo)準(zhǔn)和實(shí)踐,并提供了標(biāo)準(zhǔn)化測(cè)試來(lái)檢查問(wèn)題。WS-I 是本系列的第 6 部分將要討論的主題。
  • WS-BPEL:?jiǎn)蝹€(gè)服務(wù)很好處理,但應(yīng)用程序在大多數(shù)情況下則較難處理。企業(yè)級(jí)計(jì)算要求至少將多個(gè)服務(wù)組合為一個(gè)完整的系統(tǒng),而 WS-BPEL 提供了用于指定創(chuàng)建此類(lèi)系統(tǒng)所必需的交互(如分支和并發(fā)處理)。本系列的第 7 部分將討論 WS-BPEL。

在 Web 服務(wù)中扮演重要角色的其他規(guī)范將不在本系列中討論,其中包括 WS-ReliableMessaging(允許確定檢索一個(gè)且僅一個(gè)消息副本)、Web 服務(wù)資源框架 (WSRF)(允許使用在無(wú)狀態(tài)環(huán)境中非常重要的狀態(tài))和 Web 服務(wù)分布式管理 (WSDM)(討論 Web 服務(wù)的管理和使用問(wèn)題)??梢栽诒窘坛痰?a >參考資料中獲得有關(guān)這些規(guī)范及其他規(guī)范的更多信息。





回頁(yè)首


將要完成的工作

在本教程中,您將了解 Daily Moon 報(bào)社的 Classifieds Department 如何將其自己的系統(tǒng)與內(nèi)容管理系統(tǒng)使用的基于 Web 服務(wù)的接口進(jìn)行集成。將創(chuàng)建一個(gè)應(yīng)用程序,以創(chuàng)建基于 SOAP 的消息,將其發(fā)送到服務(wù),然后檢索響應(yīng)。完成了此工作后,您將了解如何創(chuàng)建服務(wù)來(lái)響應(yīng)請(qǐng)求并發(fā)送自己的響應(yīng)。將通過(guò)創(chuàng)建 Java 應(yīng)用程序(使用或不使用應(yīng)用服務(wù)器)來(lái)完成此工作。
 

設(shè)置

現(xiàn)在已經(jīng)了解了所涉及的基本原理,接下來(lái)讓我們看看如何實(shí)際創(chuàng)建應(yīng)用程序。首先要使所需軟件就緒。

設(shè)置 Apache Geronimo

將需要的第一個(gè)軟件是 Web 應(yīng)用服務(wù)器。為什么需要 Web 應(yīng)用服務(wù)器呢?因?yàn)槟鷷?huì)發(fā)現(xiàn),沒(méi)有 Web 應(yīng)用服務(wù)器很難提供 Web 服務(wù)。Web 應(yīng)用服務(wù)器將偵聽(tīng)請(qǐng)求,將這些請(qǐng)求轉(zhuǎn)換為實(shí)際服務(wù)可以理解的內(nèi)容,然后進(jìn)行任何必要的處理。

此過(guò)程中幾乎可以使用任何 Web 服務(wù)器,但在大多數(shù)情況下都將使用能簡(jiǎn)化此過(guò)程的軟件(通常要求使用某種類(lèi)型的實(shí)際應(yīng)用服務(wù)器)。具體來(lái)說(shuō),本教程假定您將使用 Java 應(yīng)用服務(wù)器。(實(shí)際上,將使用 J2EE 應(yīng)用服務(wù)器。)

對(duì)于 J2EE 服務(wù)器,有很多選擇;在本例中將使用 Apache Geronimo。Geronimo 是作為 IBM WebSphere Application Server Community Edition 基礎(chǔ)的開(kāi)放源代碼應(yīng)用服務(wù)器。Geronimo 很小,非常易于安裝和管理。它還能與其他 Apache 項(xiàng)目(如稍后將安裝的 Axis2)一起良好地工作。

請(qǐng)下載相關(guān)軟件(請(qǐng)參閱先決條件)并將文件提取到目標(biāo)目錄中。您會(huì)發(fā)現(xiàn)所提取的文件中包含自身的目錄,因此可以直接對(duì)其進(jìn)行解包,并可將其移動(dòng)到任何位置。任何目錄都是可接受的,但要避免名稱(chēng)中包含空格的目錄,如“Program Files”、“Documents and Settings”或其子目錄。例如,本教程的測(cè)試安裝使用的是 e:\geronimo-1.0。

就是這里。已經(jīng)在其中安裝了 Geronimo。這不是很簡(jiǎn)單么?

要啟動(dòng)此服務(wù)器,請(qǐng)打開(kāi)命令提示符窗口,并執(zhí)行以下命令:

cd <GERONIMO_HOME>
java -jar server.jar

要確保服務(wù)器正在運(yùn)行,請(qǐng)打開(kāi)瀏覽器,并指向清單 4 中所示的 URL:

            http://localhost:8080
            

應(yīng)該看到與圖 1 中所示類(lèi)似的頁(yè)面。

現(xiàn)在讓我們開(kāi)始安裝 Web 服務(wù)軟件。





安裝 Apache Axis2

完全可能從普通 HTTP 服務(wù)器提供 Web 服務(wù)。不過(guò),這樣并不明智。處理 SOAP 消息需要進(jìn)行很多工作,但沒(méi)有必要完全從頭進(jìn)行所有工作。Apache Axis 項(xiàng)目幾年前就對(duì)此任務(wù)進(jìn)行了簡(jiǎn)化,創(chuàng)建了可方便地創(chuàng)建和處理 Web 服務(wù)的環(huán)境。該軟件包含了多個(gè)應(yīng)用程序,可幫助從普通項(xiàng)目創(chuàng)建 Web 服務(wù),從 Web 服務(wù)創(chuàng)建 Java 對(duì)象,并對(duì)二者進(jìn)行處理。Apache 小組已推出了 Axis 的新版本 Axis2,該版本繼承了 Axis 上的所有已有功能,并通過(guò)更改體系結(jié)構(gòu)實(shí)現(xiàn)了更大的靈活性,從而將其推向了一個(gè)新的高度。這很重要,因?yàn)?Web 服務(wù)規(guī)范隨時(shí)都在增加。Axis2 的構(gòu)造允許它更方便與 WSS4J、Apache 的 WS-Security 實(shí)現(xiàn)等項(xiàng)目集成。由于我們將在以后使用這些項(xiàng)目,因此請(qǐng)現(xiàn)在安裝 Axis2(有關(guān)下載信息,請(qǐng)參閱先決條件)。

請(qǐng)確保同時(shí)下載 Binary Distribution 和 War Distribution。前者將幫助構(gòu)建客戶(hù)機(jī),而后者用于幫助構(gòu)建服務(wù)。

要將 Axis2 安裝到 Web 服務(wù)器中,請(qǐng)將 axis2.war 文件復(fù)制到 Geronimo 的 deploy 目錄。(您將需要確保已經(jīng)至少啟動(dòng)過(guò) Geronimo 一次,才能保證存在此目錄。)Geronimo 將自動(dòng)檢測(cè)其是否存在,因此不必手動(dòng)部署任何內(nèi)容。





驗(yàn)證 Axis 的安裝

要確保已經(jīng)恰當(dāng)安裝了所有內(nèi)容,請(qǐng)將瀏覽器指向 http://localhost:8080/axis2/index.jsp 并單擊 Validate。

應(yīng)該看到與圖 2 中所示類(lèi)似的頁(yè)面。

在繼續(xù)本教程的其他內(nèi)容前,請(qǐng)確保成功安裝了 Axis。





安裝示例服務(wù)

將要編寫(xiě)的第一個(gè)應(yīng)用程序是客戶(hù)機(jī),因此將需要其可訪問(wèn)的服務(wù)。幸運(yùn)的是,Axis2 分發(fā)版提供了若干此類(lèi)服務(wù)。首先,將按照以下所示安裝 MyService 服務(wù):

  1. 通過(guò)將瀏覽器指向 http://localhost:8080/axis2/Login.jsp 并登錄,從而通過(guò)身份驗(yàn)證。缺省用戶(hù)名和密碼分別為 adminAxis2
  2. 單擊 Upload service>Browse。
  3. 導(dǎo)航到 MyService.aar 文件??梢栽跇?biāo)準(zhǔn) Axis2 分發(fā)版的 samples\userguide 目錄下找到該文件。單擊 OK
  4. 單擊 Upload。

應(yīng)該看到一個(gè)通知,指示服務(wù)已添加(請(qǐng)參閱圖 3)。在缺省情況下,Axis2 包含“熱部署”功能,因此不必進(jìn)行任何操作來(lái)激活。

現(xiàn)在,讓我們了解一下將要構(gòu)建的內(nèi)容。
 

理解 SOAP

現(xiàn)在已經(jīng)安裝了軟件,接下來(lái)可以開(kāi)始著手處理實(shí)際的 Web 服務(wù)了。正如我在其他類(lèi)型的 Web 服務(wù)中提到的,您可以選擇多種格式。在本系列中,將使用 SOAP。

XML 簡(jiǎn)介

進(jìn)行傳遞的所有這些消息都基于可擴(kuò)展標(biāo)記語(yǔ)言(Extensible Markup Language,XML)。如果完全不熟悉 XML,在深入了解各個(gè) Web 服務(wù)主題前,真的應(yīng)該進(jìn)行一些相關(guān)研究。不過(guò),以下提供了繼續(xù)學(xué)習(xí)本教程所需的基本知識(shí)。

XML 是一種“標(biāo)記語(yǔ)言”,即給出了一種提供實(shí)際內(nèi)容的附加信息的方式。此信息以“標(biāo)記”的形式提供,這些標(biāo)記用于指示“元素”。例如,考慮一下清單 5 中所示的簡(jiǎn)單 XML 文檔。

            <article articleId="88271" categoryId="classifieds" subcategoryId="forsale">
            <articleHeadline>Fun, fun, fun</articleHeadline>
            <articleText>Vintage 1963 T-Bird.  Less than 300 miles.
            Driven by my daughter until I took it away.  Serious
            inquires only.  555-3264 after 7 PM.</articleText>
            </article>
            

請(qǐng)留意此文本中的幾個(gè)值得注意的地方。首先,這是文本。這就使其可以供任何人閱讀,或在其中包含關(guān)于任何事物的內(nèi)容。其次,標(biāo)記使用 > 和 < 指示,開(kāi)始標(biāo)記具有一個(gè)名稱(chēng),并可能帶有各種屬性(如文章 ID),而結(jié)束標(biāo)記以反斜杠 (/) 表示。元素必須為自包含的,并進(jìn)行了恰當(dāng)嵌套。也就是說(shuō),不能使用與清單 6 所示類(lèi)似的 XML 文檔。

            <article articleId="88271" categoryId="classifieds" subcategoryId="forsale">
            <articleHeadline>Fun, fun, fun
            <articleText></articleHeadline>Vintage 1963 T-Bird.
            Less than 300 miles. Driven by my daughter until I
            took it away.  Serious inquires only.  555-3264 after
            7 PM.</articleText>
            </article>
            

XML 還提供了將內(nèi)容劃分為不同“命名空間”的方法,以便由應(yīng)用程序?qū)ζ溥M(jìn)行不同的處理。例如,SOAP 消息可能與以下的清單 7 類(lèi)似。

            <?xml version=‘1.0‘ ?>
            <env:Envelope xmlns:env="http://www.w3.org/2003/05/SOAP-envelope">
            <env:Header>
            </env:Header>
            <env:Body>
            <cms:getNumberOfArticles xmlns:cms="http://www.daily-moon.com/cms">
            <cms:category>classifieds</cms:category>
            <cms:subcategory>forsale</cms:subcategory>
            </cms:getNumberOfArticles>
            </env:Body>
            </env:Envelope>
            

不要擔(dān)心消息的實(shí)際結(jié)構(gòu),但要注意存在兩種不同的“前綴”,每個(gè)前綴與特定的命名空間對(duì)應(yīng)。在這種情況下,我們是為了將 SOAP“信封”與實(shí)際的有效負(fù)載進(jìn)行區(qū)分。

再次說(shuō)明,關(guān)于 XML 有很多需要學(xué)習(xí),但這些只是本教程需要了解的基礎(chǔ)知識(shí)。





SOAP 信封

Web 服務(wù)消息的基本單元是實(shí)際的 SOAP 信封。這是包含處理消息所必需的所有信息的 XML 文檔(請(qǐng)參見(jiàn)清單 8)。

            <?xml version=‘1.0‘ ?>
            <env:Envelope xmlns:env="http://www.w3.org/2003/05/SOAP-envelope">
            <env:Header>
            </env:Header>
            <env:Body>
            </env:Body>
            </env:Envelope>
            

在本例中,獲得了一個(gè)簡(jiǎn)單的 Envelope,其命名空間指定為 SOAP 1.2 版本。其中包含兩個(gè)子元素 HeaderBody。讓我們了解一下這兩個(gè)子元素所起的作用。





SOAP Header

SOAP 消息中的 Header 用于提供有關(guān)消息本身的信息,與用于應(yīng)用程序的信息相對(duì)。例如,Header 可以包括路由信息,像清單 9 中的示例類(lèi)似。

            <?xml version=‘1.0‘ ?>
            <env:Envelope xmlns:env="http://www.w3.org/2003/05/SOAP-envelope">
            <env:Header>
            <wsa:ReplyTo xmlns:wsa=
            "http://schemas.xmlSOAP.org/ws/2004/08/addressing">
            <wsa:Address>
            http://schemas.xmlSOAP.org/ws/2004/08/addressing/role/anonymous
            </wsa:Address>
            </wsa:ReplyTo>
            <wsa:From>
            <wsa:Address>
            http://localhost:8080/axis2/services/MyService</wsa:Address>
            </wsa:From>
            <wsa:MessageID>ECE5B3F187F29D28BC11433905662036</wsa:MessageID>
            </env:Header>
            <env:Body>
            </env:Body>
            </env:Envelope>
            

本例中有一個(gè) WS-Addressing 元素,其中包含有關(guān)消息將送達(dá)何處以及應(yīng)將應(yīng)答送達(dá)何處的信息。Header 可包含關(guān)于消息本身的所有類(lèi)型的消息。事實(shí)上,SOAP 規(guī)范中使用了大量篇幅說(shuō)明哪些元素可以放入 Header以及應(yīng)由“SOAP 中間層”如何對(duì)其進(jìn)行處理。也就是說(shuō),SOAP 規(guī)范并不假定消息將直接從一個(gè)點(diǎn)傳遞到另一個(gè)點(diǎn)(從客戶(hù)機(jī)到服務(wù)器)。規(guī)范考慮了 SOAP 消息在送達(dá)最終目的地的過(guò)程中可能實(shí)際由多個(gè)中間層處理的情況,很清楚地說(shuō)明了中間層應(yīng)如何對(duì)待在 Header 中找到的信息。不過(guò),對(duì)此的討論不在本教程的范圍之內(nèi)。因此,目前只要知道 Header 可以提供許許多多的功能(如果您需要)即可。

接下來(lái)讓我們看看實(shí)際的有效負(fù)載。





SOAP 體

發(fā)送 SOAP 消息時(shí),都是有目的性的。您在嘗試告訴接收者執(zhí)行某種操作,或嘗試向服務(wù)器傳遞相關(guān)信息。此信息稱(chēng)為“有效負(fù)載”。有效負(fù)載位于 EnvelopeBody 中。它還具有自己的命名空間,在本例中其命名空間與內(nèi)容管理系統(tǒng)對(duì)應(yīng)。在此情況下,可以完全隨意地選擇命名空間。只需要與 SOAP 命名空間相異即可(請(qǐng)參見(jiàn)清單 10)。

            <?xml version=‘1.0‘ ?>
            <env:Envelope xmlns:env="http://www.w3.org/2003/05/SOAP-envelope">
            <env:Header>
            ...
            </env:Header>
            <env:Body>
            <cms:addArticle xmlns:cms="http://www.daily-moon.com/cms">
            <cms:category>classifieds</category>
            <cms:subcategory>forsale</cms:subcategory>
            <cms:articleHeadline></cms:articleHeadline>
            <cms:articleText>Vintage 1963 T-Bird.  Less than 300 miles.
            Driven by my daughter until I took it away.  Serious inquires only.
            555-3264 after 7 PM.</cms:articleText>
            </cms:addArticle>
            </env:Body>
            </env:Envelope>
            

在此例中,有效負(fù)載很簡(jiǎn)單,其中包含將文章添加到 Daily Moon 的內(nèi)容管理系統(tǒng)的指令。

如何設(shè)計(jì)有效負(fù)載的選擇過(guò)程將涉及到樣式和編碼的內(nèi)容。





樣式和編碼

本系列教程的第 2 部分將更深入地了解此主題的內(nèi)容(該部分討論 Web 服務(wù)描述語(yǔ)言——WSDL),但在創(chuàng)建應(yīng)用程序時(shí),您將需要確定要發(fā)送和接收的實(shí)際有效負(fù)載的結(jié)構(gòu)。為此,讓我們花點(diǎn)時(shí)間討論一下編程樣式和編碼。

簡(jiǎn)單來(lái)說(shuō),有兩種不同的主流 SOA 消息編程樣式。第一種是 RPC 樣式,基于使用 SOAP 消息創(chuàng)建遠(yuǎn)程過(guò)程調(diào)用(Remote Procedure Call)的概念。在此樣式中,基本思路是在向服務(wù)器發(fā)送命令(如“添加文章”),并將該命令的參數(shù)(如要添加的文章和應(yīng)該添加到的類(lèi)別)作為整個(gè)方法的子元素包含在其中,如清單 11 中所示。

            <env:Envelope xmlns:env="http://www.w3.org/2003/05/SOAP-envelope">
            <env:Header>
            

RPC 樣式的替代方法將數(shù)據(jù)直接作為 SOAP 體的內(nèi)容處理,并在應(yīng)用服務(wù)器對(duì)消息進(jìn)行路由的信息中包含有關(guān)其所屬的過(guò)程或函數(shù)的信息。(請(qǐng)參見(jiàn)清單 12)。

            <env:Envelope xmlns:env="http://www.w3.org/2003/05/SOAP-envelope">
            <env:Header>
            </env:Header>
            <env:Body>
            <cms:addArticle xmlns:cms="http://www.daily-moon.com/cms">
            <cms:category>classifieds</category>
            <cms:subcategory>forsale</cms:subcategory>
            <cms:articleHeadline></cms:articleHeadline>
            <cms:articleText>Vintage 1963 T-Bird.  Less than 300
            miles.  Driven by my daughter until I took it away.
            Serious inquires only.  555-3264 after 7 PM.</cms:articleText>
            </cms:addArticle>
            </env:Body>
            </env:Envelope>
            

RPC 樣式的一個(gè)變體就是與上面看到的 RPC/literal 相對(duì)的 RPC/encoded。在這種情況下,消息中包含類(lèi)型信息,如清單 13 中所示。

            <?xml version=‘1.0‘ ?>
            <env:Envelope xmlns:env="http://www.w3.org/2003/05/SOAP-envelope">
            <env:Header>
            </env:Header>
            <env:Body>
            <cms:addArticle xmlns:cms="http://www.daily-moon.com/cms">
            <cms:category xsi:type="xsd:string">classifieds</category>
            <cms:subcategory xsi:type="xsd:string">forsale
            </cms:subcategory>
            <cms:articleHeadline xsi:type="xsd:string" />
            <cms:articleText xsi:type="xsd:string">Vintage 1963
            T-Bird.  Less than 300 miles.  Driven by my daughter until
            I took it away.  Serious inquires only.  555-3264 after 7
            PM.</cms:articleText>
            </cms:addArticle>
            </env:Body>
            </env:Envelope>
            

第二個(gè)樣式稱(chēng)為 document/literal 樣式,即將相應(yīng)的數(shù)據(jù)直接添加到消息中,如清單 14 中所示。

            <?xml version=‘1.0‘ ?>
            <env:Envelope xmlns:env="http://www.w3.org/2003/05/SOAP-envelope">
            <env:Header>
            </env:Header>
            <env:Body>
            <category>classifieds</category>
            <subcategory>forsale</subcategory>
            <articleHeadline></articleHeadline>
            <articleText>Vintage 1963 T-Bird.  Less than 300 miles.
            Driven by my daughter until I took it away.  Serious
            inquires only.  555-3264 after 7 PM.</articleText>
            </env:Body>
            </env:Envelope>
            

在這種情況下,消息本身并不包含有關(guān)數(shù)據(jù)所提交到的進(jìn)程的信息,此工作由路由軟件進(jìn)行。例如,所有對(duì)特定 URL 或端點(diǎn)的調(diào)用都可能指向特定的操作。另外,從技術(shù)上講,可以使用 document/encoded 樣式,但目前還沒(méi)有人這樣做,因此可以將其忽略。

在每個(gè)樣式中都涉及到不同的折衷,本系列的第 2 部分將進(jìn)一步對(duì)此進(jìn)行詳細(xì)討論。不過(guò),務(wù)必知道還有第三種樣式“document wrapped”,并未正式地確定此樣式,但由于各種互操作性原因而大受歡迎。在此情況下,有效負(fù)載的內(nèi)容包裝為單個(gè)元素,但元素并不據(jù)數(shù)據(jù)所屬的過(guò)程或函數(shù)進(jìn)行命名。從肉眼來(lái)看,這些消息幾乎與 RPC/literal 消息完全相同。





消息交換模式

談到發(fā)送消息,您有很多選擇,可以發(fā)送請(qǐng)求并等待響應(yīng),發(fā)送請(qǐng)求但不等待響應(yīng),發(fā)送請(qǐng)求并在到達(dá)最終的目的地前通過(guò)多個(gè)中間層。但就實(shí)質(zhì)而言,只有兩個(gè)選擇:

  • 請(qǐng)求/響應(yīng):在請(qǐng)求/響應(yīng)模式種,以 SOAP 消息的形式發(fā)送請(qǐng)求,然后直接等待發(fā)送回響應(yīng)。請(qǐng)求可以為同步的,也可以是異步的。
  • 單向消息傳遞:這種情況也稱(chēng)為“Fire and Forget”方法,發(fā)送請(qǐng)求但并不等待響應(yīng)。可以在僅傳遞信息時(shí)或并不關(guān)心接收者對(duì)此如何響應(yīng)時(shí)使用此方法。
現(xiàn)在,請(qǐng)注意并沒(méi)有使用術(shù)語(yǔ)“客戶(hù)機(jī)”和“服務(wù)器”。之所以這樣,是因?yàn)檫@些消息交換模式幾乎可以用于創(chuàng)建與上面提到的方法類(lèi)似的任意數(shù)量的不同備選方法。例如,可以發(fā)送一條請(qǐng)求,然后依靠接收者對(duì)其進(jìn)行處理,并在將來(lái)完成應(yīng)完成的工作時(shí)發(fā)送一條消息。為此,將使用多個(gè)單向消息的組合,因此談“客戶(hù)機(jī)”和“服務(wù)器”并不合理,因?yàn)槊總€(gè)消息都有其接收方和發(fā)送方,所謂的客戶(hù)機(jī)和服務(wù)器的位置會(huì)發(fā)生對(duì)換。
 

構(gòu)建 SOAP 客戶(hù)機(jī)

上面已經(jīng)對(duì)理論進(jìn)行了介紹,現(xiàn)在讓我們開(kāi)始構(gòu)建實(shí)際的實(shí)現(xiàn)。首先從客戶(hù)機(jī)開(kāi)始。

以前的老方式

最初出現(xiàn)用于使用 SOAP 消息的 Java API 時(shí),其用途非常特定化。它們的用途相當(dāng)直接,用于創(chuàng)建 SOAP 消息。需要?jiǎng)?chuàng)建消息、EnvelopeHeader、Body 等等。例如,可以構(gòu)建“舊式”客戶(hù)機(jī)來(lái)訪問(wèn)前面安裝的 MyService 服務(wù)的 echo 函數(shù)(請(qǐng)參見(jiàn)清單 15)。

注意:為了編譯并運(yùn)行此客戶(hù)機(jī),將需要 SAAJ 實(shí)現(xiàn)(如原始 Axis 軟件)??梢詮?http://ws.apache.org/axis/ 下載 Axis。據(jù)說(shuō) Axis2 0.95 也包含此實(shí)現(xiàn),但本教程未針對(duì)其進(jìn)行測(cè)試。

            import javax.xml.SOAP.*;
            import javax.xml.transform.*;
            import java.io.FileInputStream;
            import javax.xml.transform.stream.*;
            import org.w3c.dom.*;
            public class SendSOAP {
            public static void main(String args[]) {
            try {
            MessageFactory messageFactory = MessageFactory.newInstance();
            SOAPMessage message = messageFactory.createMessage();
            //Create objects for the message parts
            SOAPPart SOAPPart = message.getSOAPPart();
            SOAPEnvelope envelope = SOAPPart.getEnvelope();
            SOAPBody body = envelope.getBody();
            SOAPElement bodyElement =
            body.addChildElement(envelope.createName("echo",
            "req", "http://localhost:8080/axis2/services/MyService/"));
            bodyElement.addChildElement("category")
            .addTextNode("classifieds");
            message.saveChanges();
            SOAPPart SOAPpartbefore = message.getSOAPPart();
            SOAPEnvelope reqenv = SOAPpartbefore.getEnvelope();
            System.out.println("REQUEST:");
            System.out.println(reqenv.toString());
            //Now create the connection
            SOAPConnectionFactory SOAPConnFactory =
            SOAPConnectionFactory.newInstance();
            SOAPConnection connection =
            SOAPConnFactory.createConnection();
            SOAPMessage reply = connection.call(message,
            "http://localhost:8080/axis2/services/MyService");
            SOAPPart SOAPpart = reply.getSOAPPart();
            SOAPEnvelope replyenv = SOAPpart.getEnvelope();
            System.out.println("\nRESPONSE:");
            System.out.println(replyenv.toString());
            connection.close();
            } catch (Exception e){
            System.out.println(e.getMessage());
            }
            }
            }
            

請(qǐng)注意,您要直接創(chuàng)建 SOAPEnvelope、SOAPBody 等內(nèi)容??梢韵蛳Ⅲw添加 echocategory 等元素。將從其中創(chuàng)建連接,進(jìn)行調(diào)用,同樣也能遍歷 SOAP 消息的結(jié)構(gòu)來(lái)獲取實(shí)際的內(nèi)容。如果要運(yùn)行此客戶(hù)機(jī),應(yīng)該看到與清單 16 中所示類(lèi)似的響應(yīng)。

            REQUEST:
            <SOAPenv:Envelope xmlns:SOAPenv=
            "http://schemas.xmlSOAP.org/SOAP/envelope/"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <SOAPenv:Body>
            <req:echo xmlns:req=
            "http://localhost:8080/axis2/services/MyService/">
            <req:category>classifieds</req:category>
            </req:echo>
            </SOAPenv:Body>
            </SOAPenv:Envelope>
            RESPONSE:
            <SOAPenv:Envelope xmlns:SOAPenv=
            "http://schemas.xmlSOAP.org/SOAP/envelope/" xmlns:wsa=
            "http://schemas.xmlSOAP.org/ws/2004/08/addressing">
            <SOAPenv:Header>
            <wsa:ReplyTo>
            <wsa:Address>
            http://schemas.xmlSOAP.org/ws/2004/08/addressing/role/anonymous
            </wsa:Address>
            </wsa:ReplyTo>
            <wsa:From>
            <wsa:Address>
            http://localhost:8080/axis2/services/MyService</wsa:Address>
            </wsa:From>
            <wsa:MessageID>ECE5B3F187F29D28BC11433905662036</wsa:MessageID>
            </SOAPenv:Header>
            <SOAPenv:Body>
            <req:echo xmlns:req=
            "http://localhost:8080/axis2/services/MyService/">
            <req:category>classifieds</req:category>
            </req:echo>
            </SOAPenv:Body>
            </SOAPenv:Envelope>
            

echo 服務(wù)所進(jìn)行的所有工作實(shí)際就是對(duì)其所接收到的請(qǐng)求進(jìn)行應(yīng)答,通過(guò)這一點(diǎn)可以很好地了解舊式處理方法與新式處理方法間的差別。接下來(lái)讓我們看看二者的差異。





新方式

現(xiàn)在越來(lái)越趨向于對(duì)程序員隱藏使用基于 XML 的 Web 服務(wù)消息的復(fù)雜性。為此進(jìn)行了大量的工作,其中大部分的目標(biāo)都是希望盡可能讓 Web 服務(wù)編程與任何其他體系結(jié)構(gòu)的編程工作一樣進(jìn)行。

在 Axis2 中,實(shí)際上并不僅限于此。Axis2 引入了一種全新的方式來(lái)使用表示 SOAP 消息的 XML(盡管表面看來(lái)與使用文檔對(duì)象模型類(lèi)似)。AxIs 對(duì)象模型(Axis Object Model,AXIOM)進(jìn)行了一系列更改,但我暫時(shí)將僅提一下其對(duì)消息的信息集的關(guān)注,消息集是元素和屬性中包含的實(shí)際信息,而不是通??吹降男蛄谢姹?。不過(guò),更為重要的是,Axis2 將為您處理 SOAP 信封,從而可以將精力放在構(gòu)建有效負(fù)載上(或者,如果是實(shí)際的服務(wù),則是分析有效負(fù)載和創(chuàng)建響應(yīng))。接下來(lái)讓我們看看如何進(jìn)行此工作。





創(chuàng)建請(qǐng)求

要開(kāi)始創(chuàng)建客戶(hù)機(jī),請(qǐng)確保 Axis2 lib 目錄中的所有 *.jar 文件——指 Standard 分發(fā)版,而不是 War 分發(fā)版——都在您的 CLASSPATH 上,并創(chuàng)建名為 ClassifiedClient 的新類(lèi)。創(chuàng)建有效負(fù)載,如清單 17 中所示。

            import org.apache.axis2.addressing.EndpointReference;
            import org.apache.axis2.client.Options;
            import org.apache.axis2.client.ServiceClient;
            import org.apache.axis2.om.OMElement;
            import javax.xml.stream.XMLOutputFactory;
            import javax.xml.stream.XMLStreamException;
            import java.io.StringWriter;
            import org.apache.axis2.om.OMAbstractFactory;
            import org.apache.axis2.SOAP.SOAPFactory;
            import org.apache.axis2.om.OMFactory;
            import org.apache.axis2.om.OMNamespace;
            public class ClassifiedClient {
            public static OMElement getEchoOMElement() {
            SOAPFactory fac = OMAbstractFactory.getSOAP12Factory();
            OMNamespace omNs = fac.createOMNamespace(
            "http://daily-moon.com/cms", "cms");
            OMElement method = fac.createOMElement("echo", omNs);
            OMElement value = fac.createOMElement("category", omNs);
            value.addChild(fac.createText(value, "classifieds"));
            method.addChild(value);
            return method;
            }
            public static void main(String[] args) {
            try {
            OMElement payload = ClassifiedClient.getEchoOMElement();
            } catch (Exception e) { //(XMLStreamException e) {
            System.out.println(e.toString());
            }
            }
            }
            

首先,創(chuàng)建工廠和命名空間,并使用其創(chuàng)建各個(gè)元素。在本例中,您將創(chuàng)建與前面示例完全相同的元素,因?yàn)閷⒃俅问褂么丝蛻?hù)機(jī)訪問(wèn) echo 函數(shù)。(稍后將對(duì)其進(jìn)行更改,以訪問(wèn)真正的服務(wù)。)

接下來(lái),將創(chuàng)建請(qǐng)求。





創(chuàng)建請(qǐng)求

下一步將創(chuàng)建實(shí)際的請(qǐng)求。同樣,這方面也體現(xiàn)出技術(shù)隨時(shí)間的發(fā)展。這里不會(huì)直接將請(qǐng)求發(fā)送到 URL,而要設(shè)置“端點(diǎn)引用”,如清單 18 中所示。

            ...
            public class ClassifiedClient {
            private static EndpointReference targetEPR = new
            EndpointReference(
            "http://localhost:8080/axis2/services/MyService");
            public static OMElement getEchoOMElement() {
            ...
            }
            public static void main(String[] args) {
            try {
            OMElement payload = ClassifiedClient.getEchoOMElement();
            Options options = new Options();
            options.setTo(targetEPR);
            options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
            } catch (Exception e) { //(XMLStreamException e) {
            System.out.println(e.toString());
            }
            }
            }
            

對(duì) WS-Addressing 的全面討論不在本教程的范疇之內(nèi),但完全可以說(shuō)端點(diǎn)引用包含消息將定向到的 URL,還可以有選擇地包含其他信息,如應(yīng)答地址和其他資源屬性等。

首先,為請(qǐng)求創(chuàng)建 Options,以便為請(qǐng)求設(shè)置 EPR 和其他信息(如打算使用的傳輸協(xié)議)。完成了這些后,就可以實(shí)際發(fā)送請(qǐng)求了。





發(fā)送請(qǐng)求

完成了設(shè)置后,就可以發(fā)送請(qǐng)求了。對(duì)于 Axis 的 0.94 版,首選的方式是通過(guò) ServiceClient 類(lèi)發(fā)送消息,如清單 19 中所示。

            ...
            public static void main(String[] args) {
            try {
            OMElement payload = ClassifiedClient.getEchoOMElement();
            Options options = new Options();
            options.setTo(targetEPR);
            options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
            ServiceClient sender = new ServiceClient();
            sender.setOptions(options);
            OMElement result = sender.sendReceive(payload);
            } catch (Exception e) { //(XMLStreamException e) {
            System.out.println(e.toString());
            }
            }
            }
            

將創(chuàng)建 ServiceClient 對(duì)象,并為其設(shè)置前面創(chuàng)建的 Options。然后就可以直接發(fā)送消息了。由于希望得到響應(yīng),因此將使用 sendReceive() 方法(該方法用于 in/out 類(lèi)型的消息)。將在本教程的單向服務(wù)部分討論單向消息的信息。sendReceive() 方法將在客戶(hù)機(jī)接收到實(shí)際響應(yīng)時(shí)將其返回。





輸出結(jié)果

實(shí)際上,sendReceive() 并不會(huì)返回整個(gè)響應(yīng),而僅返回有效負(fù)載。如果將結(jié)果輸出到命令行,應(yīng)該清楚地看到清單 20 中的內(nèi)容。

            ...
            sender.setOptions(options);
            OMElement result = sender.sendReceive(payload);
            System.out.println(result.toString());
            } catch (Exception e) { //(XMLStreamException e) {
            System.out.println(e.toString());
            }
            }
            }
            

運(yùn)行此客戶(hù)機(jī)將獲得清單 21 中所示的響應(yīng)。

            <cms:echo xmlns:cms="http://daily-moon.com/cms"><cms:catego
            ry>classifieds</cms:category></cms:echo>
            

當(dāng)然,接收到此數(shù)據(jù)后,可以使用其進(jìn)行任何工作。接下來(lái),我們將構(gòu)建實(shí)際的 getNumberofArticles() 服務(wù)。
 

構(gòu)建 SOAP 服務(wù)

如果您覺(jué)得構(gòu)建 Web 服務(wù)客戶(hù)機(jī)的過(guò)程相當(dāng)簡(jiǎn)單,事實(shí)的確如此。而就很多方面而言,構(gòu)建服務(wù)的過(guò)程也同樣簡(jiǎn)單。

總體過(guò)程

創(chuàng)建 Axis2 Web 服務(wù)的整個(gè)過(guò)程涉及以下步驟:

  1. 創(chuàng)建服務(wù)清單
  2. 創(chuàng)建類(lèi)
  3. 將其打包為 Axis 存檔文件
  4. 將 Axis 存檔文件上載到 Axis2 Web 應(yīng)用程序
  5. 重新啟動(dòng)服務(wù)器(如果有必要)

這就是全部步驟。讓我們首先從服務(wù)清單開(kāi)始。





回頁(yè)首


創(chuàng)建清單

服務(wù)清單告知 Axis2 應(yīng)用程序(就更大的范圍而言,應(yīng)用服務(wù)器)哪個(gè)請(qǐng)求與哪個(gè)類(lèi)對(duì)應(yīng)。例如,可以如清單 22 中所示的那樣指定兩個(gè)服務(wù)函數(shù)。


清單 22. 在清單中指定兩個(gè)服務(wù)函數(shù)
            <service name="CMSService">
            <description>
            This is a sample Web Service for the newspaper‘s
            Content Managment System.
            </description>
            <parameter name="ServiceClass" locked="false"
            >CMSService</parameter>
            <operation name="getNumberOfArticles">
            <messageReceiver class=
            "org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
            </operation>
            <operation name="addArticle">
            <messageReceiver class=
            "org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver"/>
            </operation>
            </service>
            

首先,定義服務(wù),提供其名稱(chēng)和描述,并指定實(shí)際為請(qǐng)求服務(wù)的類(lèi)。接下來(lái),定義實(shí)際的操作。請(qǐng)注意,此示例指定了兩種不同類(lèi)型的 messageReceiver。第一個(gè) RawXMLINOutMessageReceiver 用于傳統(tǒng)的請(qǐng)求/響應(yīng)服務(wù)。第二個(gè) RawXMLINOnlyMessageReceiver 用于單向消息。操作的名稱(chēng)與有效負(fù)載的根元素以及要執(zhí)行的方法對(duì)應(yīng)。

將此文件保存為 services.xml。

接下來(lái),讓我們創(chuàng)建實(shí)際的應(yīng)用程序。





回頁(yè)首


創(chuàng)建應(yīng)用程序

讓我們首先創(chuàng)建模擬前面看到的 echo 函數(shù)的類(lèi)(將直接返回原始有效負(fù)載的副本),如清單 23 中所示。


清單 23. CMSService 類(lèi)
            import org.apache.axis2.om.OMElement;
            import javax.xml.stream.XMLStreamException;
            public class CMSService {
            public OMElement getNumberOfArticles(OMElement element)
            throws XMLStreamException {
            element.build();
            element.detach();
            return element;
            }
            }
            

要編譯此應(yīng)用程序,請(qǐng)確保 <axis2_home>/lib 中的所有 *.jar 文件都在您的 CLASSPATH 上。

此應(yīng)用程序相當(dāng)簡(jiǎn)單,僅包含一個(gè)與 getNumbereOfArticles 操作對(duì)應(yīng)的類(lèi)。此函數(shù)和任何要作為操作的函數(shù)一樣,接收單個(gè) OMElement 參數(shù)(表示有效負(fù)載)。此處,您將首先使用 build() 方法來(lái)確定已接收到所有數(shù)據(jù)——AXIOM 使用一個(gè) pull 方法訪問(wèn)數(shù)據(jù)——然后將元素從其當(dāng)前樹(shù)中分離,以便能夠?qū)⑵浞祷亍?/p>

如果喜歡冒險(xiǎn),可以自由地部署服務(wù)訪問(wèn)服務(wù),以訪問(wèn)服務(wù)并查看結(jié)果。應(yīng)該看到與清單 24 中所示類(lèi)似的結(jié)果輸出。


清單 24. CMSService 類(lèi)響應(yīng)
            <cms:getNumberOfArticles><cms:category>classifieds</cms:category></cms:
            getNumberOfArticles>
            

接下來(lái)讓我們了解如何實(shí)際處理數(shù)據(jù)。





回頁(yè)首


提取有效負(fù)載

為了從有效負(fù)載提取信息,將使用與 DOM 非常類(lèi)似的技術(shù)來(lái)對(duì)接收到的有效負(fù)載元素進(jìn)行操作(請(qǐng)參見(jiàn)清單 25)。


清單 25. 提取有效負(fù)載信息
            ...
            import javax.xml.stream.XMLStreamException;
            public class CMSService {
            public OMElement getNumberOfArticles(OMElement element)
            throws XMLStreamException {
            element.build();
            element.detach();
            String rootName = element.getLocalName();
            OMElement categoryElement = element.getFirstElement();
            String categoryElementName = categoryElement.getLocalName();
            String categoryValue = childElement.getText();
            return element;
            }
            }
            

請(qǐng)記住,有效負(fù)載的根是 getNumberOfArticles 函數(shù)接收的元素。在此情況下,將提取元素的名稱(chēng),然后移動(dòng)到第一個(gè)元素子項(xiàng)(與第一個(gè)子項(xiàng)不同,后者可能是空格文本節(jié)點(diǎn))并提取其名稱(chēng)和值。請(qǐng)注意,使用的是 getText() 方法來(lái)提取實(shí)際上是 category 元素的文本節(jié)點(diǎn)子項(xiàng)的值。這無(wú)疑非常簡(jiǎn)捷!





回頁(yè)首


創(chuàng)建并返回響應(yīng)

最后,將需要使用從請(qǐng)求的有效負(fù)載提取數(shù)據(jù)來(lái)創(chuàng)建響應(yīng)。在本例中,將從第二個(gè)函數(shù)(在實(shí)際應(yīng)用程序中,該函數(shù)將進(jìn)行一些其他的工作)提供響應(yīng)(請(qǐng)參見(jiàn)清單 26)。


清單 26. 創(chuàng)建響應(yīng)
            ...
            import javax.xml.stream.XMLStreamException;
            public class CMSService {
            public OMElement getNumberOfArticles(OMElement element)
            throws XMLStreamException {
            element.build();
            element.detach();
            String rootName = element.getLocalName();
            OMElement childElement = element.getFirstElement();
            String childName = childElement.getLocalName();
            String categoryValue = childElement.getText();
            SOAPFactory factory = OMAbstractFactory.getSOAP12Factory();
            OMNamespace namespace = factory.createOMNamespace(
            "http://daily-moon.com/cms/", "resp");
            OMElement resultElem = factory.createOMElement(
            "numberOfArticles",namespace);
            String actualValue =
            (articleCount(categoryValue)).toString();
            resultElem.setText(actualValue);
            return resultElem;
            }
            private Integer articleCount(String catId){
            //Perform some function such as searching the CMS
            //database, and return the actual value.  For our
            //purposes, you‘ll hardcode it.
            return new Integer(42);
            }
            }
            

首先,創(chuàng)建將用于創(chuàng)建所有其他對(duì)象的工廠,然后創(chuàng)建將添加到響應(yīng)的有效負(fù)載的命名空間。接下來(lái),創(chuàng)建實(shí)際結(jié)果元素,在本例中為名為 numberOfArticles 的元素。

numberOfArticles 元素的內(nèi)容將為 articleCount() 函數(shù)返回的一個(gè)數(shù)字,在本例中,該函數(shù)可以為任何內(nèi)容。在實(shí)際的應(yīng)用程序中,將進(jìn)行所需進(jìn)行的任何工作來(lái)獲取此數(shù)據(jù)。獲取了此數(shù)據(jù)后,會(huì)將其設(shè)置為 numberOfArticles 元素的內(nèi)容,并直接返回該元素。

現(xiàn)在剩下的就是部署服務(wù)了。





回頁(yè)首


部署服務(wù)

為了部署服務(wù),需要?jiǎng)?chuàng)建一個(gè) Axis 存檔文件。此文件和 *.jar 或 *.war 文件類(lèi)似,實(shí)際是使用特殊文件擴(kuò)展名(在本例中使用的是 .aar)的 zip 文件。請(qǐng)按照以下步驟創(chuàng)建此文件:

  1. 將 <AXIS2_HOME>/lib 目錄中的所有文件添加到 CLASSPATH 并編譯 CMSService.java 文件。
  2. 在與 CMSService.class 文件相同的目錄中創(chuàng)建名為 META-INF 的新目錄。
  3. 從包含 CMSService.class 文件的目錄中發(fā)出以下命令:<code type="section" width="100"> jar cvf CMSService.aar ./* </code> 應(yīng)該看到與以下類(lèi)似的結(jié)果:<code type="section" width="100"> added manifest adding:CMSService.class(in = 513) (out= 330)(deflated 35%) adding:CMSService.java(in = 328) (out= 182)(deflated 44%) ignoring entry META-INF/ adding:META-INF/services.xml(in = 391) (out= 229)(deflated 41%) </code>
  4. 使用安裝示例服務(wù)中列出的步驟將此服務(wù)添加到服務(wù)器上。(如果看到 Web 接口上有 Servlet 錯(cuò)誤,請(qǐng)確保登錄到了 Axis2 應(yīng)用程序。如果會(huì)話已過(guò)期,應(yīng)用程序?qū)⒉灰欢〞?huì)通知您,而可能會(huì)直接顯示錯(cuò)誤。)
  5. 如果有必要,請(qǐng)重新啟動(dòng) Geronimo。(將可能不必在添加服務(wù)后進(jìn)行此操作,但在進(jìn)行更改后可能必須這樣做。)

如果單擊 View services 鏈接,應(yīng)該看到與圖 4 中所示類(lèi)似的內(nèi)容。


圖 4. 可用服務(wù)
可用服務(wù)




回頁(yè)首


訪問(wèn)服務(wù)

現(xiàn)在已經(jīng)完成了服務(wù)構(gòu)建,接下來(lái)要通過(guò)客戶(hù)機(jī)對(duì)其進(jìn)行訪問(wèn)。對(duì)前面創(chuàng)建的 ClassifiedClient.java 文件進(jìn)行以下更改(請(qǐng)參見(jiàn)清單 27)。


清單 27. 修改 ClassifiedClient
            ...
            public class ClassifiedClient {
            private static EndpointReference targetEPR =
            new EndpointReference(
            "http://localhost:8080/axis2/services/CMSService");
            public static OMElement getEchoOMElement() {
            SOAPFactory fac = OMAbstractFactory.getSOAP12Factory();
            OMNamespace omNs = fac.createOMNamespace(
            "http://daily-moon.com/cms", "cms");
            OMElement method = fac.createOMElement("getNumberOfArticles", omNs);
            OMElement value = fac.createOMElement("category", omNs);
            value.addChild(fac.createText(value, "classifieds"));
            method.addChild(value);
            return method;
            }
            public static void main(String[] args) {
            try {
            OMElement payload = ClassifiedClient.getEchoOMElement();
            Options options = new Options();
            options.setTo(targetEPR);
            options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
            ServiceClient sender = new ServiceClient();
            sender.setOptions(options);
            OMElement result = sender.sendReceive(payload);
            String response = result.getText();
            System.out.println("There are "+response+" classifieds at the moment.");
            } catch (Exception e) { //(XMLStreamException e) {
            System.out.println(e.toString());
            }
            }
            }
            

編譯并運(yùn)行了此應(yīng)用程序后,應(yīng)看到清單 28 中所示的響應(yīng)。


清單 28. ClassifiedClient 響應(yīng)
There are 42 classifieds at the moment.
 

單向服務(wù)

繼續(xù)討論之前,讓我們了解一下處理單向服務(wù)(而非請(qǐng)求/響應(yīng)服務(wù))時(shí)涉及到的不同之處。

服務(wù)

創(chuàng)建單向服務(wù)非常簡(jiǎn)單。此過(guò)程與創(chuàng)建請(qǐng)求/響應(yīng)服務(wù)完全類(lèi)似,至少不會(huì)實(shí)際返回任何內(nèi)容。例如,可以為 CMSService 類(lèi)創(chuàng)建 addArticle 操作,如圖 29 中所示。

...
            private Integer articleCount(String catId){
            ...
            }
            public void addArticle(OMElement element)
            throws XMLStreamException{
            element.build();
            System.out.println(element);
            }
            }
            

在 services.xml 文件中,將 addArticle 操作指定為“in only”操作,因此不會(huì)等待返回任何內(nèi)容,但即使這樣,也能看到會(huì)實(shí)際發(fā)生一些事項(xiàng),會(huì)在命令行輸出接收到的有效負(fù)載。您將在 Geronimo 窗口中看到此信息。

在實(shí)際應(yīng)用程序中,此方法將從有效負(fù)載提取信息,并會(huì)實(shí)際添加到某種類(lèi)型的數(shù)據(jù)庫(kù)或其他存儲(chǔ)庫(kù)。





客戶(hù)機(jī)

此服務(wù)的客戶(hù)機(jī)也與請(qǐng)求/響應(yīng)服務(wù)所使用的服務(wù)類(lèi)似(請(qǐng)參見(jiàn)清單 30)。

            import org.apache.axis2.addressing.EndpointReference;
            import org.apache.axis2.client.Options;
            import org.apache.axis2.client.ServiceClient;
            import org.apache.axis2.om.OMElement;
            import org.apache.axis2.SOAP.SOAPFactory;
            import org.apache.axis2.om.OMAbstractFactory;
            import org.apache.axis2.om.OMNamespace;
            public class AddArticleClient {
            private static EndpointReference targetEPR =
            new EndpointReference(
            "http://localhost:8080/axis2/services/CMSService");
            private static OMElement getOMElement(){
            SOAPFactory fac = OMAbstractFactory.getSOAP12Factory();
            OMNamespace omNs = fac.createOMNamespace(
            "http://daily-moon.com", "cms");
            OMElement method = fac.createOMElement("addArticle", omNs);
            OMElement category = fac.createOMElement("category", omNs);
            category.setText("classifieds");
            OMElement subcategory =
            fac.createOMElement("subcategory", omNs);
            category.setText("wantads");
            OMElement adtext = fac.createOMElement("article", omNs);
            adtext.setText("Do you  have good head for numbers"+
            " and a great deal of patience?  Do you like"+
            " to sit for hours sorting objects by their"+
            " size?  If so, then you could be the"+
            " next goober counter in the world famous"+
            " Murphy Brothers peanut factory. "+
            " Willingness to dress up as our mascot"+
            " helpful, but not required.");
            method.addChild(category);
            method.addChild(subcategory);
            method.addChild(adtext);
            return method;
            }
            public static void main(String[] args) {
            try {
            OMElement payload = AddArticleClient.getOMElement();
            ServiceClient serviceClient = new ServiceClient();
            Options options = new Options();
            serviceClient.setOptions(options);
            options.setTo(targetEPR);
            serviceClient.fireAndForget(payload);
            } catch (AxisFault axisFault) {
            axisFault.printStackTrace();
            }
            }
            }
            

盡管有效負(fù)載不同,但正如您在 getOMElement() 方法中看到的,編程方面目前的唯一真正的更改是使用 fireAndForget() 方法替代 sendReceive() 方法。此方法并不會(huì)返回響應(yīng)。

如果運(yùn)行此客戶(hù)機(jī),應(yīng)該在 Geronimo 窗口中看到與圖 5 中所示類(lèi)似的輸出。

通過(guò) GET 訪問(wèn)服務(wù)

在 SOAP 1.2 推出之前,使用 HTTP 訪問(wèn)基于 SOAP 的 Web 服務(wù)的唯一方法是使用 POST 請(qǐng)求。您將需要?jiǎng)?chuàng)建能創(chuàng)建 POST 請(qǐng)求并使用 SOAP 消息作為請(qǐng)求的內(nèi)容的客戶(hù)機(jī)。不過(guò),SOAP 1.2 定義了使用 GET 請(qǐng)求訪問(wèn)基于 SOA 的 Web 服務(wù)的方法。

GET 與 POST 對(duì)比

繼續(xù)我們的討論之前,務(wù)必了解通過(guò) HTTP 的 GETPOST 請(qǐng)求的區(qū)別。盡管很多 Web 程序員所進(jìn)行的處理似乎表明二者之間是可以互換的,但實(shí)際上二者的用途并不相同。GET 中的所有關(guān)于所請(qǐng)求的資源的信息都包含在 URL(通常作為參數(shù)),僅用于等冪請(qǐng)求。這些請(qǐng)求是沒(méi)有“副作用”的請(qǐng)求。也就是說(shuō),應(yīng)該能夠數(shù)十次、數(shù)百次、數(shù)千次地調(diào)用這個(gè)請(qǐng)求,但這個(gè)請(qǐng)求不會(huì)更改任何東西。例如,請(qǐng)求 Albuquerque 的當(dāng)前氣溫的 Web 請(qǐng)求就是等冪請(qǐng)求。而將注釋傳入到博客數(shù)據(jù)庫(kù)的 Web 請(qǐng)求則不是。

這是因?yàn)?GET 請(qǐng)求可以添加到用戶(hù)的書(shū)簽,能在不會(huì)引發(fā)警告的情況下進(jìn)行訪問(wèn)。還可以對(duì)其進(jìn)行引用,而不會(huì)引發(fā)警告。另一方面,POST 請(qǐng)求將其信息包含在請(qǐng)求的正文中,因此很難進(jìn)行隨機(jī)的重復(fù)。

就 SOAP 而言,這意味著應(yīng)該能夠?qū)H檢索信息而不進(jìn)行更改的 SOAP 請(qǐng)求使用 GET。對(duì)于進(jìn)行更改的任何操作,仍然都應(yīng)使用 POST





訪問(wèn)服務(wù)

在 Axis2 中,可以生成 GET 請(qǐng)求,服務(wù)器會(huì)將其轉(zhuǎn)換為 SOAP 消息,然后將有效負(fù)載作為結(jié)果返回。例如,請(qǐng)將瀏覽器指向清單 31 中所示的位置。

            http://localhost:8080/axis2/services/CMSService/getNumberOfArticles?category=classifieds
            

如果使用 0.94 版,將看到清單 32 中所示的響應(yīng)。

            <resp:numberOfArcticles>42</resp:numberOfArcticles>
            

不過(guò),這并不十分準(zhǔn)確。根據(jù) SOAP 1.2 建議規(guī)范,應(yīng)該能夠看到整個(gè) SOAP 響應(yīng)。這在 Axis2 將來(lái)的版本中可能會(huì)發(fā)生更改。
 

處理附件

簡(jiǎn)單 SOAP 消息的另一個(gè)變體是附件。對(duì)于附件,多年來(lái)人們?cè)缫讯炷茉?,但由于現(xiàn)在某些擴(kuò)展規(guī)范要求使用附件,因此您必須對(duì)其進(jìn)行處理。

二進(jìn)制數(shù)據(jù)和 XML

盡管 XML 是基于文本的格式,但卻不能忽略實(shí)際上是采用二進(jìn)制進(jìn)行表示的。因?yàn)檫@樣,將會(huì)有需要向 Web 服務(wù)傳遞或從其檢索二進(jìn)制信息的情況。

可以采用兩種方式中的一種來(lái)處理這種情況。第一種選擇是將二進(jìn)制數(shù)據(jù)實(shí)際包含在您的文檔中。這種情況的一個(gè)例子是將 Microsoft Word 文檔另存為 XML 文件時(shí)。如果在該文檔中嵌入了任何圖形,Word 會(huì)將其作為二進(jìn)制數(shù)據(jù)嵌入到 XML 文檔中(采用 Base64 編碼)。第二種選擇是直接引用該數(shù)據(jù),以便處理該文檔的應(yīng)用程序能夠找到此數(shù)據(jù)。一個(gè)極為常見(jiàn)的例子是 Web 瀏覽器以及其處理從 XHTML 文件引用的圖像的方式。XHTML 文本包含一個(gè) img 元素(或者,采用了更為先進(jìn)的技術(shù),則為 object 元素),該元素包含一個(gè) src 屬性,其中有指向?qū)嶋H數(shù)據(jù)的 URL。應(yīng)用程序可以隨后從該位置加載數(shù)據(jù)并相應(yīng)地進(jìn)行使用。

SOAP 文檔也是這樣。假如,如果向基于 SOAP 的服務(wù)提交了一個(gè)圖像,有兩個(gè)選擇??梢詫⒃摂?shù)據(jù)嵌入在有效負(fù)載中,或可以想辦法引用該數(shù)據(jù)。曾經(jīng)由于涉及到帶寬的一些問(wèn)題對(duì)此進(jìn)行過(guò)討論。





XML 二進(jìn)制優(yōu)化打包

XML 已經(jīng)比二進(jìn)制對(duì)應(yīng)項(xiàng)冗長(zhǎng)得多了。正因?yàn)槿绱?,它將使用更多的帶寬。那么,?dāng)考慮使用向 XML 文本文檔添加二進(jìn)制數(shù)據(jù)時(shí)的首選方法(將其編碼為 Base64)時(shí),會(huì)由于兩個(gè)或更多的因素而導(dǎo)致其尺寸增大,這就帶來(lái)了一個(gè)非常實(shí)際的問(wèn)題。

事實(shí)上,在過(guò)去的兩三年,曾經(jīng)有很多人強(qiáng)烈地批評(píng)缺乏對(duì)二進(jìn)制數(shù)據(jù)的實(shí)時(shí)支持,幾乎充斥著不滿(mǎn)的聲音,最終 W3C 開(kāi)始著手處理這個(gè)問(wèn)題。其工作的成果就是 XML 二進(jìn)制優(yōu)化打包(XML-binary Optimized Packages,XOP)。此協(xié)議提供了在 XML 文檔中可靠地引用外部數(shù)據(jù)的方法。例如,SOAP with Attachments 規(guī)范規(guī)定二進(jìn)制數(shù)據(jù)可以作為多部分 MIME 文檔的的一部分發(fā)送,由 XML 數(shù)據(jù)組成第一部分,而二進(jìn)制數(shù)據(jù)作為附加部分添加到其中。這樣做的問(wèn)題在于,盡管您的程序可能知道數(shù)據(jù)存在,但文檔并不知道這一點(diǎn)。同時(shí),還不允許對(duì)文檔進(jìn)行選擇性?xún)?yōu)化或?qū)ΠM(jìn)制數(shù)據(jù)的現(xiàn)有文檔進(jìn)行回溯處理。

XOP 通過(guò)提供一個(gè)特殊的機(jī)制來(lái)改進(jìn)這種情況,利用這種機(jī)制可選擇性地提取要優(yōu)化的信息,將其添加到多部分 MIME 消息中(其中也包括您的 SOAP 消息)并顯式地對(duì)其進(jìn)行引用。讓我們看一個(gè)例子。

例如,假定員工不想將新文章作為文本元素添加,而希望將其作為二進(jìn)制文檔從字處理程序添加。如果將該內(nèi)容包含在消息體中,將十分混亂,如清單 33 中所示:_

            <?xml version=‘1.0‘ ?>
            <env:Envelope xmlns:env="http://www.w3.org/2003/05/SOAP-envelope">
            <env:Header>
            </env:Header>
            <env:Body>
            <cms:addArticle xmlns:cms="http://www.daily-moon.com/cms">
            <cms:category>classifieds</category>
            <cms:subcategory>forsale
            </cms:subcategory>
            <cms:articleHeadline><cms:articleHeadline>
            <cms:articleText>wvetwenptiubnweoirntuwopeirt4m[456n09ew7nv
            sa0tv043u6y304o5mu60ew9rebtm45bm4-69nw-0er9utnv3094nb-26204
            95u6-49kv6-m34956h-wb09emjb-0n67u-340v,=qw-enr7w8b64b03278-
            ANDLOTSMOREBASE64ENCODEDDATAHERE</cms:articleText>
            </cms:addArticle>
            </env:Body>
            </env:Envelope>
            

相反,XOP 規(guī)定對(duì)數(shù)據(jù)進(jìn)行提取,然后使用一個(gè)引用其新位置的 Include 元素將其替換,如清單 34 中所示。

            MIME-Version: 1.0
            Content-Type: Multipart/Related;boundary=MIME_boundary;
            type="application/xop+xml";
            start="<soapmsg.xml@daily-moon.com>";
            start-info="text/xml"
            Content-Description: An XML document with binary data in it
            --MIME_boundary
            Content-Type: application/xop+xml;
            charset=UTF-8;
            type="text/xml"
            Content-Transfer-Encoding: 8bit
            Content-ID: <soapmsg.xml@daily-moon.com>
            <env:Envelope xmlns:env="http://www.w3.org/2003/05/SOAP-envelope">
            <env:Header>
            </env:Header>
            <env:Body>
            <cms:addArticle xmlns:cms="http://www.daily-moon.com/cms">
            <cms:category>classifieds</category>
            <cms:subcategory>forsale
            </cms:subcategory>
            <cms:articleHeadline><cms:articleHeadline>
            <cms:articleText><xop:Include
            xmlns:xop=‘http://www.w3.org/2004/08/xop/include‘
            href=‘cid:http://daily-moon.com/tbird.doc‘
            /></cms:articleText>
            </cms:addArticle>
            </env:Body>
            </env:Envelope>
            --MIME_boundary
            Content-Type: application/vnd.oasis.openoffice
            Content-Transfer-Encoding: binary
            Content-ID: <http://daily-moon.com/tbird.doc>
            // binary octets for the word processing file
            --MIME_boundary--
            

請(qǐng)注意,Include 元素中指定的位置與 Content-ID 減去協(xié)議 cid: 的值匹配。現(xiàn)在要發(fā)送的是此消息,而不是純文本 SOAP 消息。





SOAP、二進(jìn)制數(shù)據(jù)和 Axis2

在 SOAP 文檔中使用 XOP 的過(guò)程稱(chēng)為 MTOM(即 SOAP 消息傳輸優(yōu)化機(jī)制——Message Transmission Optimization Mechanism)。Axis2 提供了使用 SOA 數(shù)據(jù)的這個(gè)方法的支持,但必須確保對(duì)應(yīng)用程序進(jìn)行了恰當(dāng)配置。

具體來(lái)說(shuō),您必須在 axis2.war 文件內(nèi)的 axis2.xml 文件中啟用此支持(請(qǐng)參見(jiàn)清單 35)。

            <axisconfig name="AxisJava2.0">
            <!-- ================================================= -->
            <!-- Parameters -->
            <!-- ================================================= -->
            <parameter name="hotdeployment" locked="false">true</parameter>
            <parameter name="hotupdate" locked="false">true</parameter>
            <parameter name="enableMTOM" locked="false">true</parameter>
            <!-- Uncomment this to enable REST support -->
            <!--    <parameter name="enableREST" locked="false">true</parameter>-->
            <parameter name="userName" locked="false">admin</parameter>
            <parameter name="password" locked="false">axis2</parameter>
            ...
            

如果有必要,可以提取 axis2.war 文件,進(jìn)行此更改,然后將其重新壓縮成 .war 文件。

要替換 Axis2 應(yīng)用程序,請(qǐng)使用清單 36 中所示的 URL 訪問(wèn) Geronimo 控制臺(tái)。

            http://localhost:8080/console
            

作為 system/manager 登錄,并單擊 Application>Web App WARs,然后卸載并重新安裝 Axis2 應(yīng)用程序。(請(qǐng)記住,執(zhí)行此步驟后,必須重新加載 Web 服務(wù)。)

以編程方式使用 MTOM 不在本教程的討論范圍之內(nèi),但可以在參考資料部分獲取有關(guān)此主題的更多信息。只是要注意,在 Axis2 的 0.95 版之前的版本上可能不會(huì)按照預(yù)期工作,因?yàn)樵摪姹局邪?SOAP with Attachments API for Java (SAAJ) 實(shí)現(xiàn)。
 

結(jié)束語(yǔ)

在系統(tǒng)間的互操作性非常重要的當(dāng)今世界,可將 Web 服務(wù)視為面向服務(wù)的體系結(jié)構(gòu)的基礎(chǔ)。而 SOAP 則是企業(yè)級(jí) Web 服務(wù)的基礎(chǔ)。本教程介紹了 Web 服務(wù)的基礎(chǔ)知識(shí),并對(duì)了解和在自己的應(yīng)用程序中使用 SOAP 所必需的概念和編程知識(shí)進(jìn)行了說(shuō)明。在本教程中,您了解了以下內(nèi)容:

  • 有關(guān) Web 服務(wù)的重要概念
  • 如何安裝和使用 Geronimo 應(yīng)用服務(wù)器
  • 如何安裝和使用 Axis2 Web 服務(wù)應(yīng)用程序
  • 如何創(chuàng)建客戶(hù)機(jī)來(lái)訪問(wèn) SOAP 服務(wù)
  • 如何創(chuàng)建 SOAP 服務(wù)
  • 有關(guān) SOAP 服務(wù)的其他問(wèn)題,如 GET 請(qǐng)求和附件
在本系列的第 2 將討論 Web 服務(wù)描述語(yǔ)言,您將從中學(xué)習(xí)如何使用 WSDL 來(lái)實(shí)現(xiàn)在本文中執(zhí)行的很多步驟的自動(dòng)化,并提供更便于其他人訪問(wèn)您構(gòu)建的服務(wù)的方法。
 

下載

描述 名字 大小 下載方法
Source code ws-understand-web-services1.zip 12KB HTTP
 

參考資料

學(xué)習(xí)

獲得產(chǎn)品和技術(shù)
  • 此處下載 Apache Geronimo。

  • 此處下載 Apache Axis2。本教程使用的是 0.94 版,但應(yīng)該也能使用更高版本。

  • 此處下載 J2SE SDK。

關(guān)于作者

Nicholas Chase 曾參與多家公司的網(wǎng)站開(kāi)發(fā)工作,如 Lucent Technologies、Sun Microsystems、Oracle 和 Tampa Bay Buccaneers。Nick 擔(dān)任過(guò)高中物理教師、低輻射廢料處理設(shè)施管理員、在線科幻小說(shuō)雜志編輯、多媒體工程師、Oracle 講師以及一家交互通信公司的首席技術(shù)官。他已經(jīng)出版了多本圖書(shū),其中包括 XML Primer Plus (Sams)。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶(hù)發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
AXIS全攻略(二)
用Axis 1.1 for Java進(jìn)行Web Services開(kāi)發(fā)(1)
XML認(rèn)證教程,第 10 部分: Web 服務(wù)
用LoadRunner測(cè)試Web Services
SOAP凈化有線協(xié)議(一):SOAP基礎(chǔ)知識(shí)
中華網(wǎng)校-WSDL文件詳解(上)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服