SOAP例項入門(轉)
SOAP的HelloWord例項- -
1.1 前言
2005-3-2公司開會並分給我一個任務:寫一個程式從福建移動的BOSS系統取出一些相關資料。我得到的資料只有一個“福建移動BOSS與業務增值平臺介面規範V1.2.2(新).doc”,這個規範頁數不多,一下就瀏覽完了。但之後依然不知所措,感覺到了一條河邊,河前有一條大道(就是這份文件)能讓我直達目的地,但卻找不到過河的橋。這份文件只給出了資料的格式編碼規範,但沒有告訴你用什麼技術,怎麼去取這些資料,甚至連一個數據格式的XML例子檔案也沒有。
裡面只有這樣幾句話:“交易訊息(包括請求和應答)是以XML格式表達的,包括兩個部分:Message Header(訊息頭)與Service Content(交易業務內容)。” “介面協議使用HTTP協議,落地方為發起方提供訪問的URL,發起方使用HTTP POST方法傳送請求報文並得到應答報文,發起方作為落地方的HTTP客戶端,落地方作為發起方的HTTP伺服器。因此,各個參與方需要同時實現HTTP客戶端以及伺服器的功能。”
這裡面有兩個關鍵字:XML、HTTP,再加上老大說用SOAP,我想這個BOSS系統和外界的資訊交換技術也是基於SOAP實現的吧。於是我上網搜尋了一些資料,始有此文。
注:Boss Connector就是這個專案的名稱
1.2 SOAP簡介
企業系統內部各個系統之間的資訊交換一直是一個難題,在過去有DCOM、CORBA等解決方案,但都不是很完美,不是太複雜就是有缺陷。現在則較流行SOAP(全稱:Simple Object Access Protocol,簡單物件訪問協議)。
SOAP和Web Service和Apache SOAP這些新概念(應該也不算新了)常搞的人頭昏。我是這麼理解的,Web service(也稱Web服務)是一個大的概念範疇,它表現了一種設計思想。SOAP是Web service的一個重要組成部份,如果把Web service比喻成Internet,那麼SOAP就可以比喻成TCP/IP。SOAP是一種協議而非具體產品,微軟也有自己的SOAP實現產品,而Java下比較流行的SOAP實現產品就是Apache SOAP,不過它的下一個版本已經改名成AXIS了。
SOAP是通過XML檔案來做為資料轉輸的的載體,走HTTP的線路,一般企業的防火牆都開放HTTP的80埠,所以SOAP不會被防火牆阻斷,這算是SOAP的一個優點。
資訊轉輸的雙方都要求支援SOAP服務,因為XML檔案發過去,則對方需要有SOAP服務來接收,然後對方會有反饋也是XML檔案,這時你也需要安裝SOAP服務來接收,如下圖所示:
|
XML檔案轉輸到SOAP中,SOAP服務還會有一些內部處理,它具體的處理過程就暫時不管這麼多了,下面先來寫一個HelloWorld例項感受一下先。
1.3 下載
一共要下載四個軟體包,它們都是開源免費的。其中,前兩個是Apache的,後兩個是SUN網站,如下所示:
具體怎麼下載就不說了,說說要注意的事項:儘量用IE的“目標另存為”的來下載,有些用FlashGet是無法下載的。下載之前先不要關閉網頁。
下載後的版本是:JAF1.0.2 + JavaMail 1.3.2 + SOAP2.3.1 + Xerces1.4.4,如下圖所示。
下載後將它們分別解壓縮。其中,soap包有些怪異,第一次解壓得到的是一個沒有副檔名的檔案soap-bin-2.3.1,要將這個檔案加一個ZIP或JAR字尾名,然後再解壓一次。
1.4 安裝及編寫HelloWorld例項(CVS:V0001版)
本機安裝環境:WindowsXP + JDK1.4.2_06 + Tomcat5.0.28 + SOAP2.3.1
1.4.1 複製JAR檔案
1、安裝JDK和Tomcat。這樣的文章網上遍地都是,本文不再細述。它們的安裝也很簡單:安裝JDK基本是一直單擊“下一步”,裝完後我沒有設定任何環境變數,就也可以用了;Tomcat也基本是單擊“下一步”就能安裝完成。
2、分別在這四個包的解壓目錄中找到:xerces.jar、soap.jar、mail.jar、activation.jar(jaf的),將它們複製到Tomcat的“Tomcat 5.0/common/lib”目錄下,這個目錄是Tomcat的預設包目錄,在這個目錄中的所有包在Tomcat啟動時都會被自動載入。
3、將c:/jdk/lib/路徑下的tools.jar也複製到Tomcat的“Tomcat 5.0/common/lib”目錄下。
注:在顯示SOAP的管理頁面需要用到這個包,設定classpath指向c:/jdk/lib/tools.jar是沒有用的,我也從來沒有將tools.jar包加入到classpath中,也沒有設定JDK_HOME,也沒有將c:/jdk/bin加入到path路徑中,基本我安裝JDK時什麼都沒有做。
4、將soap解壓目錄的webapps目錄下的soap.war檔案,複製到Tomcat的“Tomcat 5.0/webapps”目錄下,這個目錄是Tomcat的WEB應用所在目錄,soap.war是SOAP的網站,如下圖所示:
5、重啟Tomcat服務。這時Tomcat會將“Tomcat 5.0/common/lib”目錄下新加入的包載入到記憶體中。
1.4.2 編寫SOAP程式
編寫SOAP程式分三大步:
l 編寫伺服器端的程式,此程式和普通程式沒有什麼區別
l 配置SOAP,將相關請求指向到伺服器端的程式
l 編寫客戶端的程式,客戶端的程式帶有很深的SOAP的烙印,裡面會用到很多SOAP包的類和方法。
由於我習慣用Eclipse來寫程式,以後專案也是用Eclipse來開發,所以這裡的SOAP程式也是用Eclipse來寫的。當然你也可以用記事本+JDK也編寫SOAP程式。
1、配置mysoap專案的庫引用。
將下圖所示的四個JAR包加入到專案的庫引用中。關於庫引用的設定,這裡是用“使用者庫”的方式,具體操作可以參閱這篇文章:http://blog.csdn.net/glchengang/archive/2005/02/17/291522.aspx 。在完成庫引用之後,Eclipse編寫的SOAP程式時才能使用soap相關的類。
2、建立一個新的java專案mysoap,在專案裡建立一個包“cn.com.chengang.soap.hello”,然後在包中建立兩個Java檔案,如下圖所示:
(1)HelloWorldService.java是伺服器端的程式,其程式碼如下。這個程式中只有一個方法,和其他Java程式沒有什麼差別,該方法也也很簡單就是返回一個HelloWorld字串
package cn.com.chengang.soap.hello;
public class HelloWorldService {
public String getMessage() {
return "Hello World!";
}
}
(2)HelloWorldClient.java是客戶端的訪問程式,其程式碼如下:
package cn.com.chengang.soap.hello;
import java.net.URL;
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 HelloWorldClient {
public static void main(String args[]) throws Exception {
String endPoint = "http://localhost:8080/soap/servlet/rpcrouter";
Call call = new Call();//建立一個RPC Call
call.setTargetObjectURI("urn:HelloWorldService");//遠端的服務名
call.setMethodName("getMessage");//訪問方法
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); //設定編碼風格
URL url = new URL(endPoint); //SOAP服務的網址
//開始傳送RPC請求,並返回伺服器端的應答
Response resp = call.invoke(url, "");
//檢查應答報文中是否有錯
//有錯就打印出錯資訊,沒錯就列印到正確的返回值HelloWorld
if (resp.generatedFault()) {
Fault fault = resp.getFault();
System.out.println("The Following Error Occured: ");
System.out.println(" Fault Code = " + fault.getFaultCode());
System.out.println(" Fault String =" + fault.getFaultString());
} else {
Parameter result = resp.getReturnValue();
System.out.println(result.getValue());
}
}
}
這個程式的用到了很多SOAP的類。注意:如果是兩臺電腦的話,那麼HelloWorldService.java和HelloWorldClient.java是分別獨立安裝在兩臺電腦上的,HelloWorldClient中的程式程式碼就是通過SOAP服務來呼叫HelloWorldService中的getMessage方法。
4、將HelloWorldService.java的編譯檔案HelloWorldService.class複製到Tomcat中,操作步驟如下:
(1)在“導航器”檢視的bin目錄下找到HelloWorldService.class檔案。
(2)在“Tomcat 5.0/common/classes/”路徑下新建一個“cn/com/chengang/soap/hello”目錄結構,這個目錄結構要和HelloWorldService.class的所在包名一樣的。然後將HelloWorldService.class檔案複製到此目錄下,如下圖所示。
注:還有一種方法是比較普遍使用的,就是將所有伺服器端的class檔案打成一個JAR包,然後將這個JAR包放在“Tomcat 5.0/common/lib”目錄下。
5、重啟Tomcat。
這一步不要忘記了,只有重啟Tomcat才能將common下新加入的JAR包或class檔案載入到記憶體中。
1.4.3 釋出SOAP伺服器端的程式:HelloWorldService.java
有多種方法可讓HelloWorldService這個程式註冊到SOAP服務中,本文介紹的是編寫XML檔案來註冊SOAP服務的方法
(1)HelleWorld.xml檔案。此檔案可以放置到任何地方,它和HelloWorldService.java的位置沒有必然的關係。
<?xml version="1.0"?>
<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment" id="urn:HelloWorldService">
<isd:provider type="java" scope="Request" methods="getMessage">
<isd:java class="cn.com.chengang.soap.hello.HelloWorldService" static="false"/>
</isd:provider>
</isd:service>
程式碼說明:
l urn:HelloWorldService是服務名,它要求系統唯一。這裡是取成和類名相同,你也可以取其他名稱。
l getMessage是提供的服務方法,也就是類HelloWorldService的方法名
l <isd:java class=要求填入全類名(包名+類名)
(2)設定兩個環境變數。之所以要設定這兩個變數是因為接下來的釋出命令的需要。
TOMCAT_HOME = E:/Program Files/Apache Software Foundation/Tomcat 5.0
classpath = %TOMCAT_HOME%/common/lib/soap.jar;%TOMCAT_HOME%/common/lib
/mail.jar;%TOMCAT_HOME%/common/lib/activation.jar;%TOMCAT_HOME%/common/lib/xerces.jar
(3)進入DOS視窗,並定位到HelloWorld.xml所在的目錄,然後執行如下命令(一行)。如果執行正確,則應該沒有任何顯示;如果命令錯誤則會輸出錯誤資訊。
java org.apache.soap.server.ServiceManagerClient http://127.0.0.1:8080/soap/servlet/rpcrouter deploy HelloWorld.xml
另外,再介紹其他兩個常用的命令:
顯示已經註冊的SOAP服務:
java org.apache.soap.server.ServiceManagerClient http://127.0.0.1:8080/soap/servlet/rpcrouter list
取消釋出:
java org.apache.soap.server.ServiceManagerClient http://127.0.0.1:8080/soap/servlet/rpcrouter undelpoy "urn:HelloWorldService"
命令的執行過程如下:(我把xml檔案放在e:/soaptest目錄下,該目錄就這一個檔案)
你也可以進入SOAP網站的去看看是否註冊成功了。
1.4.4 執行客戶端
在Eclipse中,將HelloWorldClient.java象一個普通Java應用程式那樣執行,得到如下結果:
可見客戶端程式HelloWorldClient通過SOAP服務呼叫了HelloWorldService的getMessage方法,並得到了一個返回結果。
在這裡我們並沒有編寫傳輸的XML檔案(前面的XML是註冊服務用的,不是一回事),這是因為SOAP包已經為我們自動完成了生成XML並傳輸到伺服器的過程。
1.5 帶引數的方法呼叫(CVS:V0002版)
上面的HelloWorld的例項中,getMessage方法是沒有引數的,這一節我們來加一個引數。
(1)將HelloWorldService.java修改如下:
package cn.com.chengang.soap.hello;
public class HelloWorldService {
public String getMessage() {
return "Hello World!";
}
public String getMessage(String str) {
return "Hello World! " + str;
}
public String getMessage(String str1, String str2) {
return "Hello World! " + str1 + "&" + str2;
}
}
(2)將HelloWorldService.class複製到Tomcat的“Tomcat 5.0/common/classes/cn/com/chengang/soap/hello”目錄下,覆蓋原來的HelloWorldService.class。
(3)重啟Tomcat服務。
(4)修改HelloWorldClient程式如下(紅字部份是新加的):
package cn.com.chengang.soap.hello;
import java.net.URL;
import java.util.Vector;
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 HelloWorldClient {
public static void main(String args[]) throws Exception {
String endPoint = "http://localhost:8080/soap/servlet/rpcrouter";
Call call = new Call();//建立一個RPC Call
call.setTargetObjectURI("urn:HelloWorldService");//遠端的服務名
call.setMethodName("getMessage");//訪問方法
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); //設定編碼風格
Vector params = new Vector();
Parameter p1 = new Parameter("name", String.class, "陳剛", null);
Parameter p2 = new Parameter("name2", String.class, "陳勇", null);
params.addElement(p1);
params.addElement(p2);
call.setParams(params);
URL url = new URL(endPoint); //SOAP服務的網址
//開始傳送RPC請求,並返回伺服器端的應答
Response resp = call.invoke(url, "");
//檢查應答報文中是否有錯
//有錯就打印出錯資訊,沒錯就列印到正確的返回值HelloWorld
if (resp.generatedFault()) {
Fault fault = resp.getFault();
System.out.println("The Following Error Occured: ");
System.out.println(" Fault Code = " + fault.getFaultCode());
System.out.println(" Fault String =" + fault.getFaultString());
} else {
Parameter result = resp.getReturnValue();
System.out.println(result.getValue());
}
}
}
(6)在Eclipse中執行HelloWorldClient,得到如下效果