SOAP淨化有線協議(二):Apache SOAP介紹(2)

來源:互聯網
上載者:User
apache 三、帶有JavaBean的HelloWorld執行個體
如前所述,Apache SOAP提供了許多預先構造的序列化和反序列化方法,其中包括為利用Java Vector、Enumeration、數組、JavaBean作為參數和傳回值而提供的序列化器和反序列化器。在這一部分,我將修改HelloWorld服務,通過一個JavaBean傳入接收Hello資訊的使用者名稱。

3.1、HelloWorld服務
改寫後的HelloWorld服務完整代碼如下:


package hello;
public class HelloServer
{
public String sayHelloTo(String name)
{
System.out.println("sayHelloTo(String name)");
return "Hello " + name + ", How are you doing?";
}
public String sayHelloTo(Name theName)
{
System.out.println("sayHelloTo(Name theName)");
return "Hello " + theName.getName() + ", How are you doing?";
}
}
服務的代碼仍舊很簡單,仍舊類似於不用JavaBean時的HelloWorld服務。不過,這意味著最複雜的工作都轉移到了用戶端。事實上,這個版本的服務與以前版本的唯一差別在於,現在出現了一個重載的sayHelloTo()方法。上面的代碼中重載後的方法用粗體字顯示。

重載的方法需要一個對Name JavaBean的引用。Name JavaBean的定義如下:


package hello;
public class Name
{
private String name;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
3.2、部署服務
部署一個使用了JavaBean的服務時,需要為Apache SOAP伺服器提供一些額外的資訊。因此,現在部署服務的過程稍微複雜一點。

■ 使用管理工具部署服務

要使用管理工具部署這個新版的HelloWorld服務,首先按照前面所介紹的步驟進行,但這一次不要點擊Deploy按鈕。現在,在Number of Mappings輸入框輸入1,它表示我們將給出一個映射(即Name JavaBean)的資訊。緊接Mappings之下有一個表格,我們要用到這個表格的第一行。保留Encoding Style的值為SOAP,把NameSpace URI設定成對象的ID:在本例中,它是urn:Hello。接下來,把Local Part和Java Type輸入框設定成Name JavaBean的完整名字,即hello.Name。最後,把Java to XML Serializer和XML to Java Deserializer輸入框設定成org.apache.soap.encoding.soapenc.BeanSerializer,這是一個實現了Serializer和Deserializer介面的類,用來序列化和反序列化Name JavaBean。如果你用到了更多的JavaBean(比如還有一個Address Bean),則應該在這個表格中輸入其他Bean的資訊,同時還應該更新Number of Mappings輸入框的值,使之反映出表格中實際被使用的行數。

■ 從命令列部署服務

要從命令列進行部署,我們只需修改作為命令列參數傳入的XML部署描述器檔案。修改後的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:mappings>
<isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:x="urn:Hello" qname="x:hello.Name"
javaType="hello.Name"
java2XMLClassName="org.apache.soap.encoding.soapenc.BeanSerializer"
xml2JavaClassName="org.apache.soap.encoding.soapenc.BeanSerializer"/>
</isd:mappings>
</isd:service>
正如在前一個例子中,這些XML代碼所包含的資訊和通過Web介面的管理工具所提供的資訊一樣。

3.3、HelloWorld客戶程式
和第一個例子一樣,客戶程式更複雜,也更令人感興趣。這裡我不再仔細分析整個客戶程式,而是介紹兩個客戶程式版本的不同之處。由於調用方法的一個參數(在本例中,它是唯一的參數)是一個JavaBean,所以必須手工設定一個類型映射註冊項。這個任務通過如下步驟完成:先建立org.apache.soap.encoding.SOAPMappingRegistry類的一個執行個體,然後調用它的mapTypes()方法。正如mapTypes()方法名字所預示的,它用來註冊一個以前未知的類型,比如定製的JavaBean。mapTypes()方法的參數包括要使用的編碼方式、限定的JavaBean名字、類型的完整類名、序列化器和反序列化器。在本例中,執行序列化任務的是標準的Bean序列化器。限定的JavaBean名字包含一個元素的名字,包括它所屬的名稱空間。在本例中,Name JavaBean的限定名字由名稱空間URI(urn:Hello)和本地名字(hello.Name)結合構成。請看下面的代碼片斷:


// 建立類型映射註冊器
SOAPMappingRegistry smr = new SOAPMappingRegistry();
BeanSerializer beanSer = new BeanSerializer();
// 映射類型
smr.mapTypes(Constants.NS_URI_SOAP_ENC,
new QName("urn:Hello", "hello.Name"),hello.Name.class, beanSer, beanSer);
接下來,客戶程式必須告訴Call對象使用新的註冊器而不是預設的註冊器。為此,我們要調用Call對象的setSOAPMappingRegistry()方法,如下所示:

call.setSOAPMappingRegistry(smr);
手工設定好類型映射註冊器之後,接下來還必須為Call對象設定參數。這一步驟可以按前面介紹的方法完成,不同之處在於,現在我們不再用字串類型的名字作為參數,而是用JavaBean作為參數,如下所示:


// 設定調用參數
Vector params = new Vector();
Name theName = new Name();
theName.setName(name);
params.addElement(new Parameter("name", hello.Name.class, theName, null));
call.setParams(params);
客戶程式剩下的部分和原來的版本一樣。Listing 3顯示了完整的客戶程式碼:


Listing 3: Client2.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;
import org.apache.soap.encoding.SOAPMappingRegistry;
import org.apache.soap.encoding.soapenc.BeanSerializer;
import org.apache.soap.util.xml.QName;

public class Client2
{
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 = new Call();
call.setTargetObjectURI("urn:Hello");
call.setMethodName("sayHelloTo");
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
// 建立類型映射註冊器
SOAPMappingRegistry smr = new SOAPMappingRegistry();
BeanSerializer beanSer = new BeanSerializer();
// 映射類型
smr.mapTypes(Constants.NS_URI_SOAP_ENC,
new QName("urn:Hello", "hello.Name"),
hello.Name.class, beanSer, beanSer);
call.setSOAPMappingRegistry(smr);
// 設定參數
Vector params = new Vector();
Name theName = new Name();
theName.setName(name);
params.addElement(new Parameter("name", hello.Name.class,
theName, 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();
}
}
}
四、編譯和運行程式
現在整個程式的開發工作已經完成,該是運行它的時候了。不過,我們首先要編譯服務程式和客戶程式。

建立一個hello目錄,把Client1.java、Client2.java和HelloServer.java複製到這個目錄。我把hello目錄放到了Apache SOAP的樣本目錄(即E:\soap-2_0\samples)之下。編譯器時,classpath中只需包含hello目錄的父目錄(即E:\soap-2_0\samples)、soap.jar和xerces.jar。我用下面的批命令編譯器:


set CLASSPATH=E:\soap-2_0\samples\;E:\soap-2_0\lib\soap.jar;E:\xerces-1_2_0\xerces.jar
javac -d .. HelloServer.java Client.java Client2.java
注意:從hello目錄執行這個批命令檔案。

要使用這個服務,除了部署它之外,還需要修改Web伺服器的classpath,確保Web服務能夠找到hello.HelloServer類——對於本例,這是指把E:\soap-2_0\samples加入到Web伺服器的classpath。對classpath進行必要的修改之後,重新啟動Web伺服器。接下來就可以運行客戶程式了。下面是我運行hello.Client的批命令檔案:

set CLASSPATH=E:\soap-2_0\samples\;E:\soap-2_0\lib\soap.jar;E:\xerces-1_2_0\xerces.jar
java hello.Client Tarak
這裡的classpath和編譯器時用的classpath相同。

最後,運行hello.Client2的批命令檔案可以如下:

set CLASSPATH=E:\soap-2_0\samples\;E:\soap-2_0\lib\soap.jar;E:\xerces-1_2_0\xerces.jar
java hello.Client2 Tarak
觀察Web伺服器的控制台視窗,看看在運行兩個不同的客戶程式時,HelloWorld服務的哪些方法正在被調用。

■ 結束語
在這篇文章中,我介紹了如何用Apache SOAP實現來建立簡單的基於SOAP的服務。在SOAP實現方面,另一個重要的競爭者是Microsoft。遺憾的是,“純”Java開發人員在使用Microsoft實現的時候會有一段艱苦的時光,因為它的實現包含了COM對象。

在下一篇文章中,我將介紹Apache SOAP支援的另一種建立服務的方式:使用JavaScript之類的指令碼語言,而不是Java。另外,我還要介紹一個很不錯的JavaScript引擎,即Rhino。
■ 參考資源
  • W3C的SOAP 1.1規範:
    http://www.w3.org/TR/SOAP/
  • 下載Apache SOAP:
    http://xml.apache.org/dist/soap/
  • 有關IBM SOAP工程的更多資訊:
    http://www.alphaworks.ibm.com/tech/soap4j
  • Apache SOAP可用功能的一個清單:
    http://xml.apache.org/soap/features.html
  • Apache許可協議:
    http://www.apache.org/LICENSE.txt
  • 下載Tomcat 3.1
    http://jakarta.apache.org/builds/jakarta-tomcat/release/v3.1.1/bin/
  • 下載Apache Xerces 1.2版本:
    http://xml.apache.org/dist/xerces-j/
  • "MS SOAP SDK vs IBM SOAP4J: Comparison & Review," James Snell (O'Reilly):
    http://windows.oreilly.com/news/soapreview_0600.html


相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。