国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

SOAP凈化有線協議(二):Apache SOAP介紹(1)

2024-07-21 02:21:49
字體:
來源:轉載
供稿:網友
  • 網站運營seo文章大全
  • 提供全面的站長運營經驗及seo技術!
  •   soap(簡單對象訪問協議)是一種利用xml編碼數據的有線協議。它是同類協議中要求最低的一個規范,只定義了有線協議所要求的最關鍵的部分,有意地忽略了垃圾收集、對象激活等方面的細節。

    soap對于java開發者來說尤其重要,因為它讓平臺無關和可移植的java程序更容易協同操作,使得java的寶貴特性進一步增值。事實上,如果java 2平臺企業版(j2ee)的下一個版本讓soap成為一種必須遵循的有線協議,規定所有遵從j2ee規范的應用服務器都必須支持soap協議,我也不會感到奇怪。不過就現在來說,我想我的猜想應該暫停了。

    這個系列的文章總共四篇,這是第二篇。在這里,我要介紹的是apache soap實現。

    一、apache soap概述
    apache soap,即apache software foundation對soap規范的實現,建立在ibm的soap4j的基礎上。和所有其他apache工程類似,apache soap源代碼開放,按照apache許可協議發行。我覺得這是當前最好的soap實現之一。然而,雖然apache soap遵從soap規范1.1版本,但它缺乏soap 1.1所包含的某些功能(參見本文最后的“參考資源”,了解apache soap支持功能的清單)。

    1.1、下載和安裝apache soap
    如前所述,apache soap可以免費下載(參見“參考資源”中提供的下載鏈接)。我為我的windows nt便攜機下載了soap-bin-2.0.zip文件,該文件包含apache soap 2.0,這是寫作本文時的最新版本。安裝apache soap可謂輕而易舉,共包含如下三個簡單的步驟:

    1. 解開下載所得文件的zip壓縮:解開壓縮之后就得到了一個soap-2_0子目錄。我把zip文件的內容解壓縮到e盤的根目錄下,因此有了一個包含apache soap的e:/soap-2_0目錄。
    2. 配置web環境:要有一個支持servlet和jsp的web服務器。至此,你可能遇到下面兩種情況之一:
      • 情況1:已經有一個支持servlet和jsp的web服務器,而且你覺得配置這個服務器沒有問題。在這種情況下,請配置服務器,使得瀏覽器可以訪問http://localhost:8080/apache-soap/,打開soap-2_0 /webapps/soap/目錄下面的index.html文件。
      • 情況2:沒有支持servlet和jsp的web服務器,或者雖然有這樣一個服務器,卻不想拿它做試驗。在這種情況下,我建議你下載tomcat的最新版本(寫作本文時,最新版本是3.1)(參見“參考資源”中的鏈接)。tomcat是apache創建和免費提供給軟件開發者的又一個優秀軟件。下載合適的zip文件之后(jakarta-tomcat-3.1.1.zip),解開壓縮時創建一個jakarta-tomcat子目錄。和前面相似,我把解壓縮得到的文件放入e盤的根目錄之下。在jakarta-tomcat/conf/server.xml配置文件中增加一個新的<context>標記,如下所示: <context path="/apache-soap" docbase="e:/soap-2_0/webapps/soap"
        debug="1" reloadable="true">
        </context>在context元素的docbase屬性中,你應該在指定soap-2_0目錄時把e:替換成合適的盤符。要啟動tomcat,執行startup.bat(對于unix,執行startup.sh)。要關閉tomcat,執行shutdown.bat(對于unix,執行shutdown.sh)。但請稍等——現在請不要啟動tomcat。
    3. 設置web服務器classpath:apache soap要求有1.1.2版本或更高的apache xerces(java),它支持dom(文檔對象模型)level 2規范,支持名稱空間。我使用1.2版本的xerces,即apache網站的xerces-j-bin.1.2.0.zip。解開這個壓縮文件,得到xerces-1_2_0子目錄。和前面一樣,我把解壓縮得到的文件放到了e:盤的根目錄之下。你應該配置web服務器,使它能夠用xerces.jar(它在xerces-1_2_0子目錄下)進行所有xml解析——而不是用服務器附帶的庫或jar解析xml。例如,tomcat附帶了一個xml解析器(jakarta-tomcat/lib/xml.jar),支持dom level 1接口。即使你把xerces.jar放入了classpath,tomcat下運行的java代碼也可能找錯接口,因為在用來啟動tomcat的shell腳本/批命令文件中,xerces.jar被放到了classpath的最后。因此,必須編輯jakarta-tomcat/bin目錄下的tomcat.bat(對于unix,則是tomcat.sh),把xerces.jar放到classpath的前面。下面是我在jakarta-tomcat/bin/tomcat.bat文件中所作的修改: set classpath=e:/xerces-1_2_0/xerces.jar;%classpath%;%cp%

    如果你在第二個步驟中屬于情況2,也必須配置服務器,使它能夠使用xerces.jar。

    不管你屬于哪一種情況,除了配置xerces.jar之外,你還必須配置web服務器的classpath使它能夠使用soap-2_0/lib/目錄下的soap.jar。

    1.2、檢查安裝是否成功
    現在,啟動web服務器,用瀏覽器打開http://localhost:8080/apache-soap/admin,驗證安裝是否成功。這時,你應該看到下圖所示的管理屏幕。


    圖一:web界面的apache soap管理工具

    二、實例:helloworld
    現在你已經設置好了apache soap,我們來實際使用一下,構造一個簡單的helloworld應用。在soap術語中,應用稱為服務。一般地,創建服務分兩個步驟,這兩個步驟可能由同一個人或組織實施,也可能不是。第一個步驟是在選定的語言中定義和實現服務本身,這里我們選擇java語言。第二個步驟是創建實際調用服務的客戶程序。首先我們來看helloworld服務。

    2.1、helloworld服務
    我在第一篇文章中討論了一個用soap實現的helloworld服務實例。這個服務要求輸入一個用戶名字,返回一個定制的hello消息給調用者。下面的代碼顯示了helloworld服務的完整java代碼。


    package hello;
    public class helloserver
    {
    public string sayhelloto(string name)
    {
    system.out.println("sayhelloto(string name)");
    return "hello " + name + ", how are you doing?";
    }
    }
    這就是全部的代碼嗎?如果這是真的話,實在太簡單了!

    apache soap使創建服務變得極其簡單。服務主要由業務邏輯構成,不管服務以哪種方式提供給外界使用,業務邏輯代碼都是必須編寫的。換句話說,服務不會和任何soap相關的代碼混合,因為apache soap底層體系——它由rpcrouter servlet和soap.jar構成——幫助我們完成了所有錯綜復雜的工作。我們來簡要地探討一下這些錯綜復雜的工作究竟包含些什么,例如,apache soap如何處理http上的遠程過程調用(rpc)請求?理解這一點將給創建客戶程序帶來方便(不錯,是客戶程序)。

    在apache soap中,org.apache.soap.rpc包支持在soap上進行rpc調用。apache rpc支持的關鍵在于對象id。所有的apache soap服務必須有一個唯一的id,它被視為服務的對象id。眾所周知,唯一性是一個相對的概念;在apache soap中,對象id的唯一性相對于服務所部署的apache soap服務器而言。也就是說,部署在不同apache soap服務器上的兩個服務可能有同樣的對象id。

    想要使用服務的客戶程序設置一個org.apache.soap.rpc.call對象,指定目標服務的對象id、待調用方法的名字以及提供給方法的參數(如果有的話)。設置好call對象之后,客戶程序調用它的invoke()方法。invoke()方法需要兩個參數,第一個參數是一個執行rpcrouter servlet的url,如http://localhost:8080/apache-soap/servlet/rpcrouter;第二個參數是soapaction頭(請參考本系列的第一篇文章,了解soapaction頭的重要性和可能的取值)。

    invoke()方法把call對象轉換成xml soap請求(類似第一篇文章所提供的示例),把請求發送給第一個參數中的url所指定的rpcrouter servlet。當servlet返回應答,invoke()方法返回一個org.apache.soap.rpc.response對象,這個對象包含了服務的應答(如果有的話)或錯誤信息(如果出現了錯誤)。http規定每一個請求都必須有一個應答;因此,即使服務本身不返回任何東西,rpcrouter servlet總是會返回一些內容。因此,invoke()方法總是返回一個response對象。

    在服務端,apache soap服務器(也就是rpcrouter servlet)接收客戶程序發送的soap請求,重新構造出call對象。servlet使用重新構造得到的call對象中的對象id在服務管理器中確定具體的對象。

    接下來,servlet在已經確定的對象上檢驗被調用方法的名字并調用方法。完成后,servlet串行化該調用的返回值,在http應答中把它發送給客戶程序。

    從上述討論中,我們可以發現一個有趣的問題:apache soap如何知道串行化某種給定數據類型的方法?apache soap通過一個類型注冊器(org.apache.soap.encoding.soapmappingregistry),以及通過所有裝配器(marshaller)和反裝配器(marshaller)分別必須實現的串行化(org.apache.soap.util.xml.serializer)和反串行化(org.apache.soap.util.xml.deserialization)接口,實現java數據類型和xml之間的裝配和反裝配。apache soap提供了許多實現這些接口的內建的裝配器和反裝配器。例如,我們可以用org.apache.soap.encoding.soapenc.beanserializer類裝配和反裝配javabean。本文后面我將介紹如何使用這個類。

    對于java基本數據類型(int,long,double,等等)及其對應的對象化形式(integer,long,double,等等)來說,它們的串行化器和反串行化器已經預先在類型映射注冊器中注冊。因此,對于客戶程序來說,用java基本數據類型及其對象形式作為方法參數是無縫的。然而,如果服務所要求的參數是一個javabean,則必須手工在類型映射注冊器中注冊beanserializer。服務永遠不會做任何額外的工作,最后客戶程序的負擔總是較多。在這個系列的第四篇文章中,我將介紹用動態代理構造的框架,它將使創建客戶程序和創建服務程序一樣簡單。

    2.2、部署helloworld服務
    部署apache soap服務有兩種方法:使用web界面的管理工具,或通過命令行進行部署。所有這兩種方法都可以部署服務,使服務可被客戶程序訪問。

    ■ 使用管理工具部署服務

    要使用管理工具,用瀏覽器打開http://localhost:8080/apache-soap/admin。瀏覽器將顯示出圖一所示的界面。點擊窗口左邊的deploy按鈕,一個帶有許多輸入框的窗口就會出現。并非所有的輸入框現在都要用到。我將在用到這些輸入框的時候介紹它們的含義。由于本文無需用到所有的輸入框,所以我們將忽略部分輸入框的含義。但不用擔心,到第三篇文章結束時,我將介紹完所有的輸入框。

    id輸入框用來設置對象id;如前所述,soap基礎設施利用對象id把rpc請求綁定到soap服務。我在前面已經提到,所有apache soap服務必須有一個對象id,這個對象id在該服務器上部署的所有服務之間唯一。我通常使用“urn:<uniqueserviceid>”格式,其中uniqueserviceid是服務的唯一對象id。在本例中,把id設置成“urn:hello”。

    scope輸入框用來定義響應調用請求的服務實例的生存范圍和時間。scope可以是下列值之一:

  • page:服務實例一直有效,直至應答發送完畢或把請求傳遞給了另一個頁面——如果使用標準的部署機制,向前傳遞請求不太可能發生。
  • request:服務實例在請求處理期間一直有效,不管是否出現請求傳遞。
  • session:服務實例對于整個會話都有效。
  • application:服務實例被用于所有對服務的調用請求。
      scope的值對安全有著重要的影響,記住這一點很重要。page和request值確保了連續調用之間的隔離。在另一個極端,application值意味著所有soap的用戶共享服務實例。細心的讀者可能已經注意到,jsp的<jsp:usebean>標記同樣要用到這些值。事實上,rpcrouter servlet曾經就是一個jsp頁面,這也許是這些值被選用的原因。在本例中,我們把scope的值設置成application。

      在methods輸入框中,輸入用空白字符分隔的方法名字,這些方法名字指示出當前部署的服務上允許調用的方法。我們的服務示例只支持一個方法,即sayhelloto()。

      把provider type設置成java。它意味著服務用java實現,而且你必須為apache soap提供服務完整的類名。這個任務在provider class輸入框完成,我們把它設置成hello.helloserver。由于sayhelloto()方法不是靜態的,保持static輸入框原來的值,即no。

      現在滾動到頁面的下方,點擊表單下面的deploy按鈕(不是左邊的deploy按鈕)。要驗證服務已經部署完畢,點擊左邊的list按鈕,這時列表所顯示的服務中應該包含一個urn:hello服務。

      ■ 從命令行部署服務

      部署服務除了可以用web界面的管理工具,還可以用命令行java工具org.apache.soap.server.servicemanagerclient,它是一個apache soap附帶的類。這個類要求有兩個必不可少的參數,一個指向apache soap路由servlet(即rpcrouter)的url,以及一個動作。這個動作可以是以下四者之一:deploy,undeploy,list,或query。根據指定動作的不同,有時候還要提供額外的參數。例如,如果動作是deploy,則必須提供xml部署描述器文件的名字。部署描述器文件應該包含apache soap服務器成功部署服務所需要的全部信息。例如,描述helloworld部署細節的部署xml文件可以如下:


      <isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment"
      id="urn:hello">
      <isd:provider type="java" scope="application" methods="sayhelloto">
      <isd:java class="hello.helloserver" static="false"/>
      </isd:provider>
      </isd:service>
      上述xml代碼所包含的信息和我們在web界面的管理工具中所輸入的信息一樣。接下來,輸入下面的命令,從命令行部署helloworld服務:


      java org.apache.soap.server.servicemanagerclient
      http://localhost:8080/apache-soap/servlet/rpcrouter
      deploy deploymentdescriptor.xml
      deploymentdescriptor.xml是上面顯示的描述部署信息的xml文件名字。要驗證服務是否部署成功,輸入以下命令:


      java org.apache.soap.server.servicemanagerclient
      http://localhost:8080/apache-soap/servlet/rpcrouter query urn:hello
      這時,我們應該看到和deploymentdescriptor.xml文件內一樣的xml。

      2.3、helloworld客戶程序
      編寫客戶程序要比編寫helloworld服務復雜得多。不過,你應該不會對此感到奇怪,因為前面已經提到,客戶程序(至少)必須負責設置call對象,這需要不少工作。順便說一下,本系列文章的第四篇將介紹一個框架,這個框架以java 2 1.3版新引入的動態代理類為基礎,使創建客戶程序和創建服務一樣簡單。

      listing 1顯示了完整的客戶程序。接下來我們一步一步地仔細看看這個程序。這個程序需要一個必不可少的參數:程序要向他說hello信息的用戶名字。


      listing 1: client.java
      package hello;
      import java.net.url;
      import java.util.vector;
      import org.apache.soap.soapexception;
      import org.apache.soap.constants;
      import org.apache.soap.fault;
      import org.apache.soap.rpc.call;
      import org.apache.soap.rpc.parameter;
      import org.apache.soap.rpc.response;

      public class client
      {
      public static void main(string[] args) throws exception
      {
      if(args.length == 0)
      {
      system.err.println("usage: java hello.client [soap-router-url] ");
      system.exit (1);
      }
      try
      {
      url url = null;
      string name = null;
      if(args.length == 2)
      {
      url = new url(args[0]);
      name = args[1];
      }
      else
      {
      url = new url("http://localhost:8080/apache-soap/servlet/rpcrouter");
      name = args[0];
      }
      // 構造call對象
      call call = new call();
      call.settargetobjecturi("urn:hello");
      call.setmethodname("sayhelloto");
      call.setencodingstyleuri(constants.ns_uri_soap_enc);
      vector params = new vector();
      params.addelement(new parameter("name", string.class, name, null));
      call.setparams(params);
      // 發出調用
      response resp = null;
      try
      {
      resp = call.invoke(url, "");
      }
      catch( soapexception e )
      {
      system.err.println("caught soapexception (" + e.getfaultcode() + "): " +
      e.getmessage());
      system.exit(-1);
      }

      // 檢查應答
      if( !resp.generatedfault() )
      {
      parameter ret = resp.getreturnvalue();
      object value = ret.getvalue();
      system.out.println(value);
      }
      else
      {
      fault fault = resp.getfault();
      system.err.println("generated fault: ");
      system.out.println (" fault code = " + fault.getfaultcode());
      system.out.println (" fault string = " + fault.getfaultstring());
      }
      }
      catch(exception e)
      {
      e.printstacktrace();
      }
      }
      }
      客戶程序首先設置call對象,它需要如下信息:

    • 被調用服務的對象id,它通過call對象的settargetobjecturi()方法設置。本例的對象id是urn:hello。
    • 待調用方法的名字,它通過call對象的setmethodname()方法設置。本例的方法名字是sayhelloto()。
    • 參數的編碼方式,它通過call對象的setencodingstyleuri()方法設置。本例我們使用標準的soap編碼方式,這種編碼方式由名稱空間http://schemas.xmlsoap.org/soap/encoding/定義。
    • 方法調用的參數通過call對象的setparams()方法設置。setparams()方法的參數是一個java vector(向量)。這個向量包含所有的參數,向量中索引為0的參數是被調用方法從左邊數起的第一個參數,索引為1的參數是被調用方法從左邊數起的第二個參數,依此類推。向量中的每一個元素都是一個org.apache.soap.rpc.parameter的實例。parameter構造函數要求指定參數的名字、java類型和值,還有一個可選的編碼方式。如果指定了null編碼方式(正如本例所做的那樣),則默認使用call對象的編碼方式。雖然每一個參數對應著一個名字,但這個名字可以設置成任何內容,apache soap服務器調用方法時不會用到這個名字。因此,絕對有必要讓向量中參數的次序和被調用方法的參數次序一致。
        下面的代碼片斷顯示了客戶程序創建call對象的過程:


        // 構造call對象
        call call = new call();
        call.settargetobjecturi("urn:hello");
        call.setmethodname("sayhelloto");
        call.setencodingstyleuri(constants.ns_uri_soap_enc);
        vector params = new vector();
        params.addelement(new parameter("name", string.class, name, null));
        call.setparams(params);
        現在,該是實際調用helloworld遠程服務所提供方法的時候了。為此,客戶程序調用了call對象的invoke()方法,這個方法返回一個org.apache.soap.rpc.response對象,如下所示:


        // 發出調用
        response resp = null;
        try
        {
        resp = call.invoke(url, "");
        }
        catch( soapexception e )
        {
        system.err.println("caught soapexception (" + e.getfaultcode() + "): " +
        e.getmessage());
        system.exit(-1);
        }
        接下來,客戶程序檢查response對象。如果方法調用過程中出現了錯誤,generatefault()方法返回一個true值,客戶程序提取并顯示實際的錯誤信息:


        fault fault = resp.getfault();
        system.err.println("generated fault: ");
        system.out.println (" fault code = " + fault.getfaultcode());
        system.out.println (" fault string = " + fault.getfaultstring());
        如果方法調用成功,則客戶程序提取并顯示hello信息:


        // 檢查應答
        if( !resp.generatedfault() )
        {
        parameter ret = resp.getreturnvalue();
        object value = ret.getvalue();
        system.out.println(value);
        }
      • 發表評論 共有條評論
        用戶名: 密碼:
        驗證碼: 匿名發表
        主站蜘蛛池模板: 汝阳县| 黄大仙区| 游戏| 民勤县| 扶风县| 昭平县| 镇坪县| 长沙县| 新田县| 公安县| 三门峡市| 永仁县| 南靖县| 门源| 通城县| 冀州市| 抚州市| 柯坪县| 阜阳市| 阳春市| 明水县| 湖北省| 嘉兴市| 宿迁市| 武夷山市| 无为县| 双江| 三门峡市| 崇礼县| 临夏县| 河源市| 涿鹿县| 凤台县| 古蔺县| 开原市| 梓潼县| 兴化市| 岳西县| 无极县| 北川| 丹寨县|