級別: 初級
劉冬 (winter.lau@163.com), 軟件工程師
2003 年 7 月 01 日
本文介紹使用AXIS作為開發環境來體會Web服務的開發過程。
一. 介紹
本文并不是想介紹Web服務的原理、系統架構等,我們假設您已經了解了關于Web服務的一些基本的概念、原理等知識。本文主要是針對那些已經了解Web服務概念,但是還沒有親身體會Web服務所帶來令人歡欣鼓舞的特征的開發人員。在此我們認為你已經具備了Java、XML等基礎知識,如果你還有其他開發環境的經驗例如VB、VC那是再好不過的了。
1.Web服務
雖然我們并不想詳細講述Web服務的體系結構,但是大概的介紹一下還是有必要的。Web服務是一種新型的Web應用程序。不同于其他Web應用程序,它是自適應、自我描述、模塊化的應用程序,并可以跨越Web進行發布、定位以及調用。簡單的Web服務可以提供例如天氣預報或者航班信息的服務。一旦部署了Web服務,其他的應用程序就可以發現和調用所部署的服務。
2.AXIS項目
Axis框架來自 Apache 開放源代碼組織,它是基于JAVA語言的最新的 SOAP 規范(SOAP 1.2)和 SOAP with Attachments 規范(來自 Apache Group )的開放源代碼實現。有很多流行的開發工具都使用AXIS作為其實現支持Web服務的功能,例如JBuilder以及著名的Eclipse J2EE插件Lomboz。AXIS的最新版本是1.1,可以從 http://ws.apache.org/axis/index.html下載。下圖是AXIS核心引擎的體系結構圖:
圖1
整個AXIS項目包括以下幾個部分:
- 消息流子系統
消息流子系統提供了靈活的消息傳遞框架,這個消息傳遞框架包括處理程序、鏈、序列化程序和反序列化程序。處理程序是一個處理請求、響應和故障流的對象。處理程序可被組合在一起成為鏈,而且可以使用一個靈活的部署描述符來配置這些處理程序的順序。
- 傳輸框架子系統
提供了一個傳輸框架,這個傳輸框架可以幫助您創建自己的可插式傳輸發送器和傳輸偵聽器。
- 數據編碼子系統
AXIS完全按照 XML Schema 規范提供各種數據類型的自動序列化,并且提供功能擴展接口來使用您自己定制的序列化器和反序列化器。
- 其他
AXIS完全支持 WSDL 以及日志記錄、出錯以及故障處理機制。它同時提供一些工具用來講WSDL文檔轉換成客戶端的調用框架以及根據類來產生WSDL定義文檔。
AXIS目前版本支持的標準是:W3C SOAP 1.1 和 1.2;WSDL 1.1;SAAJ 1.1(SUN公司:SOAP with Attachments API for Java);JAX-RPC(SUN公司:Java API for XML-Based RPC)1.0。
除了前面介紹的AXIS外,本文中還將會用到TOMCAT,這里不再另行介紹。另外為了演示Web服務真正與開發環境無關以及AXIS產生的是標準的、符合規范的Web服務,我們還將用到微軟公司的SOAP TOOLKIT以及微軟的開發環境VB和VC來做為Web服務的客戶端。
二. 環境搭建
由于AXIS本身是基于JAVA語言開發的項目,并且是以Web應用形式發布的,因此它運行時需要一個應用服務器作為支撐。為了方便我們這里選用的是Tomcat。由于AXIS本身需要用到處理XML信息的包,所以我們建議使用JDK1.4并安裝Tomcat 4.1.24。下面是環境搭建步驟,讀取根據自身情況進行安裝。
- 安裝JDK1.4.1
- 安裝Tomcat 4.1.24到C:\Tomcat并驗證安裝是否成功
- 下載AXIS項目打包文件axis-1_1.zip解壓縮后將目錄中的webapps目錄下的axis子目錄拷貝到C:\Tomcat\webapps下。
- 驗證AXIS的安裝:重新啟動Tomcat服務器后打開瀏覽器輸入網址http://localhost:8080/axis 后應該出現如下圖所示頁面,點擊鏈接"Validate"來驗證Axis所需的幾個JAVA包是否齊全。
圖2
點擊超鏈接Validate后,AXIS會自動檢查所需的每一個JAVA組件,這協組件分為:必需組件以及可選組件,必須保證所有必需組件都存在,如下圖所示即為驗證成功。
圖3
三. Web Service服務端開發
經過了前兩步之后我們就可以開始Web服務之旅了!大多數人在學習一種編程語言的第一步都是從Hello world程序開始的,我們也不例外。我們將提供這樣一個Web服務,通過給它傳入姓名,服務返回:你好[姓名],歡迎來到Web服務的世界。這就是我們的需求。我們將馬上根據AXIS的要求完成我們的需求,你就會發現原來Web服務可以這么簡單!
編寫JAVA類Hello.java,內容如下:
public class Hello{
public String hello(String name){
if(name==null)
name = "";
return "你好"+name+",歡迎來到Web服務的世界!";
}
}
|
僅此而已,無需編譯,將該文件改名為Hello.jws并拷貝到AXIS應用目錄C:\Tomcat\webapps\axis下。
下面我們就可以測試該Web服務了,打開瀏覽器并輸入剛剛創建的文件名對應的URL地址 http://localhost:8080/axis/Hello.jws 瀏覽器顯示如下結果:
點擊頁面上的鏈接查看該Web服務對應的WSDL信息如下所示(我們將在下一小節簡單介紹WSDL)
<?xml version="1.0" encoding="UTF-8" ?>
-<wsdl:definitions
targetNamespace="http://localhost:8080/axis/Hello.jws"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://www.w3.org/2000/xmlns/"
xmlns:apachesoap="http://xml.apache.org/xml-soap"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:impl="http://localhost:8080/axis/Hello.jws"
xmlns:intf="http://localhost:8080/axis/Hello.jws"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
- <wsdl:message name="helloRequest">
<wsdl:part name="name" type="xsd:string" />
</wsdl:message>
+ <wsdl:message name="helloResponse">
- <wsdl:portType name="Hello">
- <wsdl:operation name="hello" parameterOrder="name">
<wsdl:input name="helloRequest" message="intf:helloRequest" />
<wsdl:output name="helloResponse" message="intf:helloResponse" />
</wsdl:operation>
</wsdl:portType>
- <wsdl:binding name="HelloSoapBinding" type="intf:Hello">
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
- <wsdl:operation name="hello">
<wsdlsoap:operation soapAction="" />
- <wsdl:input name="helloRequest">
<wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://DefaultNamespace" />
</wsdl:input>- <wsdl:output name="helloResponse">
<wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://localhost:8080/axis/Hello.jws" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
- <wsdl:service name="HelloService">
- <wsdl:port name="Hello" binding="intf:HelloSoapBinding">
<wsdlsoap:address location="http://localhost:8080/axis/Hello.jws" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
|
到此我們已經完成了hello的Web服務了,那我們怎么告訴用戶如何來使用該服務呢?我們只需要告訴用戶我們的Web服務的URL地址: http://localhost:8080/axis/Hello.jws?wsdl 就可以了!下一節我們將介紹如何通過這個地址來訪問對應的Web服務。
四. Web Service客戶端開發
在這一節中我們將使用三種不同的語言來訪問剛剛創建的Web服務,分別是JAVA、VB、VC。為了使用VB和VC訪問Web服務,我們需要安裝微軟公司的Soap Toolkit 開發工具包,這個工具包可以從微軟公司的主頁
http://download.microsoft.com/download/xml/soap/2.0/W98NT42KMe/EN-US/SoapToolkit20.exe
下載,下載該軟件包并使用默認方式安裝即可。
在開始客戶端開發之前有兩個概念我們必須先粗略的介紹一下。
SOAP:簡單對象訪問協議。這是一種在松散的、分布的環境中使用XML對等地交換結構化的和類型化的信息提供了一個簡單且輕量級的機制,它是一個基于XML的協議。它包括四個部分:SOAP封裝(envelop),封裝定義了一個描述消息中的內容是什么,是誰發送的,誰應當接受并處理它以及如何處理它們的框架;SOAP編碼規則(encoding rules),用于表示應用程序需要使用的數據類型的實例; SOAP RPC表示(RPC representation),表示遠程過程調用和應答的協定;SOAP綁定(binding),使用底層協議交換信息。
雖然這四個部分都作為SOAP的一部分,作為一個整體定義的,但他們在功能上是相交的、彼此獨立的。特別的,信封和編碼規則是被定義在不同的XML命名空間(namespace)中,這樣使得定義更加簡單。
SOAP的主要設計目標是簡明性和可擴展性。這就意味著有一些傳統消息系統或分布式對象系統中的特性將不包含在SOAP的核心規范中。這些特性包括:分布式垃圾收集;批量消息傳輸/處理;對象引用;對象激活。
WSDL:Web Service描述語言。使用了WSDL,我們就可以通過這種跨平臺和跨語言的方法使Web Service代理的產生自動化。就像COM和CORBA的IDL文件,WSDL文件由客戶和服務器約定。由于WSDL設計成可以綁定除SOAP以外的其他協議,這里我們主要關注WSDL在HTTP上和SOAP的關系。同樣,由于SOAP目前主要用來調用遠程的過程和函數,WSDL支持SOAP傳輸的文檔規范。
WSDL文檔可以分為兩部分。頂部分由抽象定義組成,而底部分則由具體描述組成。抽象部分以獨立于平臺和語言的方式定義SOAP消息,它們并不包含任何隨機器或語言而變的元素。這就定義了一系列服務,截然不同的網站都可以實現。
1. JAVA客戶端
使用AXIS的工具將使Web服務的訪問和我們之前介紹的創建一個Web服務一樣的簡單。我們前面安裝的AXIS環境中已經包含著這樣的工具,它是一個JAVA類,類名為:org.apache.axis.wsdl.WSDL2Java。打開命令行窗口,轉到AXIS目錄下的WEB-INF子目錄。確保Tomcat服務已經處于啟動狀態,鍵入命令 :
Java -Djava.ext.dirs=lib org.apache.axis.wsdl.WSDL2Java http://localhost:8080/axis/Hello.jws?wsdl
|
該命令執行的結果是在當前所在目錄下產生一個子目錄 localhost/axis/Hello_jws,該目錄下有四個JAVA源文件,它們分別是:
Hello.java 定義了Web服務接口,此例中只有一個hello方法。
HelloService.java 定義了用于獲取Web服務接口的方法。
HelloServiceLocator.java 接口HelloService的具體實現。
HelloSoapBindingStub.java Web服務客戶端樁,通過該類與服務器交互。
這四個JAVA類幫我們處理了大部分的邏輯,我們需要的僅僅是把這些類加到我們的項目然后創建一個我們自己的類來調用它們即可。為此我們新加一個類Main.java,為了方便,讓這個類與剛產生的四個類都在同一個包下。內容如下:
//Main.java
package localhost.axis.Hello_jws;
public class Main{
public static void main(String[] args) throws Exception{
HelloService service = new HelloServiceLocator();
Hello hello = service.getHello();
System.out.println("Response:"+hello.hello("罐頭"));
}
}
|
使用以下命令進行編譯:
javac -classpath lib\axis.jar;lib\jaxrpc.jar localhost\axis\Hello_jws\*.java
|
如果編譯沒有問題的話執行該測試程序:
java -Djava.ext.dirs=lib -cp . localhost.axis.Hello_jws.Main//運行結果:Response:你好罐頭,歡迎來到Web服務的世界!
|
在WSDL2Java工具自動產生的幾個類中,類HelloServiceLocator中保存這一些跟服務器相關的信息,例如URL地址等,當服務器的地址更改后但是服務并沒有改動的時候直接修改該文件中的字符串定義,而無需重新生成這幾個類。具體需要修改的內容,打開該文件便可一目了然。
2. VB客戶端
有了微軟SOAP toolkit,用VB調用Web服務也是一件令人愉快的事情。
打開VB開發環境新建一個標準EXE項目,打開工程(Project)菜單并選擇引用打開組件引用對話框如下圖所示:找到并選中Microsoft Soap Type Library。
圖 4
新建并編輯窗體如下圖所示:
圖 5
編輯按鈕Call的點擊事件處理程序如下:(注意窗體的控件名稱要與程序中的名稱對應)
Private Sub callBtn_Click()
'這種做法需要在工程中引用Soap Type Library
'Dim soap As MSSOAPLib.SoapClient
'Set soap = New MSSOAPLib.SoapClient
Dim soap
Set soap = CreateObject("MSSOAP.SoapClient")
On Error Resume Next
'soap.mssoapinit urlText.Text
Call soap.mssoapinit(urlText.Text)
If Err <> 0 Then
MsgBox "初始化SOAP失?。?" + Err.Description
urlText.SetFocus
Else
If Len(Trim(nameText.Text)) = 0 Then
MsgBox "請輸入您的姓名!"
nameText.SetFocus
Else
responseText.Text = soap.hello(nameText.Text)
End If
End If
End Sub
|
保存項目并運行,輸入姓名并點擊按鈕Call。
3. VC客戶端
打開VC開發環境,新建項目HelloClient,項目類型為 Win32 Console Application的空項目。新建C++ Source File文件名為:HelloSoap.cpp,編輯文件內容如下:
//#include "stdafx.h"
#include <stdio.h>
#import "msxml3.dll"
using namespace MSXML2;
//根據自己機器的情況修改下面語句中指定的路徑
#import "C:\Program Files\Common Files\MSSoap\Binaries\mssoap1.dll" \
exclude("IStream", "ISequentialStream", "_LARGE_INTEGER", \
"_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")
using namespace MSSOAPLib;
void Hello(){
ISoapSerializerPtr Serializer;
ISoapReaderPtr Reader;
ISoapConnectorPtr Connector;
// Connect to the service
Connector.CreateInstance(__uuidof(HttpConnector));
Connector->Property["EndPointURL"] = "http://localhost:8080/axis/Hello.jws?wsdl";
Connector->Connect();
// Begin message
Connector->BeginMessage();
// Create the SoapSerializer
Serializer.CreateInstance(__uuidof(SoapSerializer));
// Connect the serializer to the input stream of the connector
Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));
// Build the SOAP Message
Serializer->startEnvelope("","","");
Serializer->startBody("");
Serializer->startElement("hello","","","");
Serializer->startElement("name","","","");
Serializer->writeString("罐頭");
Serializer->endElement();
Serializer->endElement();
Serializer->endBody();
Serializer->endEnvelope();
// Send the message to the web service
Connector->EndMessage();
// Let us read the response
Reader.CreateInstance(__uuidof(SoapReader));
// Connect the reader to the output stream of the connector
Reader->Load(_variant_t((IUnknown*)Connector->OutputStream), "");
// Display the result
printf("Response: %s\n", (const char*)Reader->RPCResult->text);
}
int main()
{
CoInitialize(NULL);
Hello();
CoUninitialize();
return 0;
}
|
編譯并運行該項目。
本節只是為了演示如果通過VC來訪問使用AXIS創建的Web服務,至于Soap toolkit的具體使用請參照soap toolkit的幫助手冊,其他語言的訪問請查閱相關的文檔。
五. AXIS集成
為了讓我們的WEB應用程序支持Web服務功能,我們需要將AXIS集成到我們的應用程序中。集成AXIS很簡單,首先需要拷貝AXIS用到的幾個JAR包文件,這些文件都在[AXIS]\WEB-INF\lib目錄下,將這些文件拷貝到我們自己的應用目錄下的WEB-INF\lib。另外如果你用的不是TOMCAT服務器那就需要拷貝activation.jar,這個JAR文件可以在[TOMCAT]\common\lib目錄下找到!
拷貝完JAR文件后就是web.xml的配置了,只需要把AXIS中的web.xml中的配置信息添加到我們自己應用程序中的web.xml中即可。最重要的是下面的內容:
<servlet>
<servlet-name>AxisServlet</servlet-name>
<display-name>Apache-Axis Servlet</display-name>
<servlet-class>
org.apache.axis.transport.http.AxisServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>*.jws</url-pattern>
</servlet-mapping>
<mime-mapping>
<extension>wsdl</extension>
<mime-type>text/xml</mime-type>
</mime-mapping>
<mime-mapping>
<extension>xsd</extension>
<mime-type>text/xml</mime-type>
</mime-mapping>
|
六 總結
到此文章告一段落,通過以上的演練,我相信你已經對Web服務有一個感性的認識,但是這個僅僅是開始,我們也只是很簡單的介紹了Web服務的一些基本概念并演示了一個無法再簡單的例子。Web服務還有很多其他高級的內容例如復雜類型、數據安全等沒有涉及到,不過沒有關系,萬事開頭難,希望本文能夠促進大家理解和應用下一代的應用模式并給還沒有動手試驗的開發人員開一個好頭。
參考資料
|