Axis Web Service開發指南
這篇文章主要是翻譯了Axis用戶指南部分。介紹瞭如何使用Axis開發WebService。有些地方可能有出入,其中也省略了一部分,不過這都不影響你如何使用Axis開發WebService。 E-mail[email protected]
1.1調用Axis上的Web服務
注意:程序源代碼 請查看官方網站!
1.1.1一個簡單的例子
執行一下命令部署服務:
啓動服務器,默認端口8080。部署服務後需要重新啓動服務器。
% java org.apache.axis.client.AdminClient samples/example1/deploy.wsdd
%cp samples /axis/WEB-INF/classes/
首先讓我們來看一個簡單的webservice客戶程序,它將調用Axis服務器上的一個echoString方法
1 import org.apache.axis.client.Call;
2 import org.apache.axis.client.Service;
3 import javax.xml.namespace.QName;
4
5 public class TestClient {
6 public static void main(String [] args) {
7 try {
8 String endpoint =
9 " http://localhost:8080/axis/services/TestServer";
10
11 Service service = new Service();
12 Call call = (Call) service.createCall();
13
14 call.setTargetEndpointAddress(new java.net.URL(endpoint) );
15 call.setOperationName(new QName("http://soapinterop.org/", echoString"));
16
17 String ret = (String) call.invoke( new Object[] { "Hello!" } );
18
19 System.out.println("Sent 'Hello!', got '" + ret + "'";
20 } catch (Exception e) {
21 System.err.println(e.toString());
22 }
23 }
24 }
你可以執行一下命令運行該程序
%javac samples.example1.TestClient.java
%java samples.example1.TestClient
Sent 'Hello!', got 'Hello!'
%
程序是如何調用服務運行的呢?在11和12行我們創建了一個Service和Call對象,它們都是用來存放關於服務調用數據的標準JAX-RPC對象。在14行我們提供了終端URL——它指定了我們SOAP信息的目的地。在15行我們指定了調用的webservice的方法.,並且在17行我們調用了我們期望的服務.,同時傳遞一個數組參數——這裏只是一個String。
你可以通過查看發送的SOAP請求來了解怎麼傳遞這個參數。
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns1:echoString xmlns:ns1="http://soapinterop.org/">
Hello!
這裏的String參數自動的被格式化爲XML,服務端返回同樣的String。就像我們上面看到的一樣。
1.1.2爲參數命名
在上面的例子中,Axis自動的把XML格式的參數在SOAP消息中直接命名爲“arg0”,“agr1”,如果你想改變這一點,很容易,在你調用invoke()之前你需要對每一個參數調用addParameter和setReturn,例如:
call.addParameter("testParam",org.apache.axis.Constants.XSD_STRING,
javax.xml.rpc.ParameterMode.IN);
call.setReturnType(org.apache.axis.Constants.XSD_STRING);
這樣的話將把testParam分配給調用方法的第一參數,也同時定義了參數的類型,以及說明了是輸入、輸出或者是輸入輸出參數,這裏是一個輸入參數。運行程序你將得到如下消息:
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
Hello!
這的參數名稱就是我們期望的testParam了。
1.1.3與”無類型”Server的互操作
在上面的例子中,我們已經映射了invoke()的返回類型到一個Object,我們知道echoString方法返回一個String,所以我們希望從client.invoke()這裏返回一個String。現在讓我們看一下這是怎麼發生的。下面是一個典型的echoString方法的響應:
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
type="xsd:string">Hello!
請看我們加粗的部分——這個屬性是一個schema 類型聲明,Axis用它來指出那個元素內容是什麼類型,這裏將把它反串行化爲一個JAVA String對象。但是在其他情況下會返回如下響應:
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
Hello, I'm a string!
消息中沒有指定類型,我們是否知道元素的反串行化結果是個什麼java 對象?答案就是原數據——數據的數據。在這種情況下我們就需要指定我們期望的返回類型。下面說明了Axis的客戶端程序該怎麼做。
call.setReturnType( org.apache.axis.Constants.XSD_STRING );
這個方法將告訴Axis客戶程序,如果返回的元素沒有定義類型,那麼它將等同於在SOAP中使用type屬性做如下定義xsi:type="xsd:string"。
這裏有個同樣功能的方法,它允許你指定期望返回類型的Java類。
call.setReturnClass(String.class);
現在我們已經瞭解了一個客戶程序訪問一個SOAP服務的基本知識。下面我們將說明如何發佈自己的服務。
1.2使用Axis發佈服務
假如我們有一個象下面一樣的簡單類:
public class Calculator {
public int add(int i1, int i2) {
return i1 + i2;
}
public int subtract(int i1, int i2) {
return i1 - i2;
}
}
我們怎樣才能使它通過SOAP訪問呢?這裏將有幾種答案,但是我們將從Axis提供的最簡單的方法開始,實現它可以說毫不費力。
1.2.1Jws文件——即時部署
第一步:複製上面的類到webapps目錄,並重命名爲Calcalator.jws。你將使用下面命令:
%copy Calculator.java /axis/Calculator.jws
第二步:你已經完成了部署。你可以通過下面的連接來訪問服務:
http://localhost:8080/axis/Calculator.jws (這裏假定你Axis服務端口8080)
Axis將自動定位該文件,編譯該文件,並且正確的轉換SOAP調用到你的服務程序。
我們可以運行calculator客戶端程序來測試結果:
% java samples.example2.CalcClient -p8080 add 2 5
Got result : 7
% java samples.example2.CalcClient -p8080 subtract 10 9
Got result : 1
%
注意:jws服務主要被簡單服務使用,你不能使用包,你不能發現錯誤直到你服務部署之後,因爲代碼只有在運行的時候纔去編譯。
1.2.2自定義部署——wsdd
Jws文件可以很快的把你的java類部署成web service,但是不是最好的選擇。因爲,你需要源代碼——但是很多時候你可能想部署一個已經存在的沒有源代碼class文件。你可以做的配置比較有限,比如怎樣訪問一個服務是受限制的——你不能定義自定義類型的映射,或者不能控制調用那一個Handlers當用戶調用服務時。
通過描述符文件來部署服務
爲了更靈活的使用Axis,你應該熟悉Axis 的Web Service Deployment Descriptor(WSDD)文件格式。下面我們來看一個基本服務的部署描述符。
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
非常簡單,最外層元素告訴引擎這是一個WSDD部署文件,並且定義了java的名字空間,接下來的service元素定義了我們的服務。一個服務就是一個targeted chain,意味着它將有下面的一個或多個:一個請求流,一個Handler,一個響應流。這裏我們的provider是Axis內置的java:RPC ,這說明這是一個Java RPC服務。爲了讓RPCProvider能夠調用正確的方法,我們使用標籤,一個參數定義服務的類名,另一個參數告訴引擎這個類的任何public方法都可以通過SOAP調用。
使用AdminClient
一旦我們有了wsdd文件,我們需要把它送給Axis服務器來具體的部署描述的服務,我們通過AdminClient,或者"org.apache.axis.client.AdminClient"來實現這一點,如果你的Axis不是部署在Tomcat中,你可能需要使用-p 參數。默認端口是8080,AdminClient工具的一個典型調用如下:
% java org.apache.axis.client.AdminClient deploy.wsdd
Done processing
這個命令將使我們的服務可以通過SOAP來進行訪問。可以通過運行客戶程序來驗證這一點:
% java samples.example3.MyClient -lhttp://localhost:8080/axis/services/MyService
"test me!"
You typed : test me!
%
你也可以使用下面命令來列出服務器上部署的所有的服務:
% java org.apache.axis.client.AdminClient list
更多的部署
現在讓我們來了解Axis引擎更強大的特性,假設你想知道你的服務被調用了多少次,我們在sample/log下有一個簡單的handler來實現這一點。要使用這個handler類,你需要首先部署它,然後你使用你給他指定的名字來部署服務,下面是一個簡單的部署文件:
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
第一部分定義了一個稱作track的Handler,它是由LogHandler類實現的,我們同時使用了參數指定了寫入log的文件。
這樣我們就定義了一個web服務,LogTestService,它和我們看到的RPC服務是一樣的。不同的地方是在元素內我們包含了元素——這意味着當你調用這個服務時需要執行一些Handlers。通過引入一個track,我們保證了每次調用服務都會寫如日誌。
1.3 Java數據類型如何映射到SOAP/XML類型
互操作性是SOAP實現的一種挑戰,如果你想讓你的服務可以和其他平臺或其他語言實現的服務一起工作,那麼你就需要了解這個問題。Java類型和WSDL/XSD/SOAP類型的之間的映射是由JAX-RPC定義的,下面是它們之間的簡單關係:
WSDL到Java標準映射
xsd:base64Binary |
byte[] |
xsd:boolean |
boolean |
xsd:byte |
byte |
xsd:dateTime |
java.util.Calendar |
xsd:decimal |
java.math.BigDecimal |
xsd:double |
double |
xsd:float |
float |
xsd:hexBinary |
byte[] |
xsd:int |
int |
xsd:integer |
java.math.BigInteger |
xsd:long |
long |
xsd:QName |
javax.xml.namespace.QName |
xsd:short |
short |
xsd:string |
java.lang.String |
1.3.1在嚴格的互操作下Axis能通過SOAP發送什麼呢?
Java Collections
一些Collection類,比如hashtable,它確實用自己的serializers,但是沒有和其他SOAP實現進行互操作的標準,並且沒有任何關於轉化複雜對象的SOAP標準。最可信賴的方法是通過數組來傳遞對象集合。
1.3.2通過SOAP Axis不能發送什麼呢?
任何沒有預先註冊的對象。
我們不能發送一個任意的Java對象,並且期望對方能夠理解。使用RMI你可以發送和接收序列化的java對象,那是因爲兩端都使用的是Java。Axis只能發送那些能被註冊的Axis序列化器序列化的對象。下面將介紹怎麼使用BeanSerializer來序列化任意一個符合JavaBean格式的類。
1.3.3編寫自己的Bean——使用BeanSerializer。
Axis不需要你書寫任何代碼就有能力seriliae/deserialize任意一個符合get/set存取的JavaBeam格式的類。你需要做的就是告訴Axis把那一個java類映射到那一個XML Schema類型,設置一個bean映射看起來是這個樣子:
languageSpecificType="java:my.java.type"/>
這裏的標籤映射一個java類到一個XML QName。你將注意到它有兩個重要的屬性,qname和languageSpecificType。這個例子中我們映射java:my.java.type類到XML QName [someNamespace]:[local]
現在來讓我們看看在實際應用中它是怎麼工作的。我們看例子samples/example5/BeanService.java,我們將看到服務方法的參數一個Order對象。因爲Order對象不是Axis能理解的一個基本類型,如果不進行映射運行這個程序我們將得到一個fault。但是我們在我們的部署文件中加入beanMapping,它將能很好的運行。下面是運行的結果:
% java org.apache.axis.client.AdminClient -llocal:///AdminService deploy.wsdd
Done processing
% java samples.userguide.example5.Client -llocal://
Hi, Glen Daniels!
You seem to have ordered the following:
1 of item : mp3jukebox
4 of item : 1600mahBattery
If this had been a real order processing system, we'd probably have charged
you about now.
%
當Bean不能滿足你的需要時可以自定義序列化器,可以參考前面章節。
1.4使用Axis的WSDL
9.1.4.1獲取部署服務的WSDL
當你使用Axis發佈一個服務,將會有唯一一個URL對應這個服務。對JWS文件來說,它的URL就是指向jws文件自己。對非jws服務,具體的URL就是:“http://:/axis/services/”。
如果你使用瀏覽器通過URL訪問服務,你將看到一個信息指出這是一個Axis服務,並且你應該通過SOAP來訪問它。如果你在URL後面加上“?wsdl”,Axis將自動生成服務的描述文件wsdl。你可以告訴你的在線夥伴通過這個連接來獲取這個服務的WSDL,這樣他們就能使用工具,比如.NET,SOAP或者其他支持WSDL的工具來訪問你的服務。
1.4.2 WSDL2Java :從WSDL來建立stubs,skeletons和數據類型。
客戶端bindings:
Axis的WSDL-TO-Java工具是"org.apache.axis.wsdl.WSDL2Java"。你可以使用下面方式調用工具:
% java org.apache.axis.wsdl.WSDL2Java (WSDL-file-URL)
這樣就會產生客戶程序需要的bindings,當從WSDL生成客戶端的bindings時Axis遵守JAX-RPC標準。我們執行一下命令:
% cd samples/addr
% java org.apache.axis.wsdl.WSDL2Java AddressBook.wsdl
產生的文件存放在AddressFetcher2目錄下,把它們放在這個目錄下是因爲把WSDL中的target namespace映射成了Java packages。
至於WSDL的各各部分是怎麼映射到響應的java程序,請看前面章節。我們這裏只探討一下複雜類型bean的映射過程。
從WSDL類型生成的java類,將在使用WSDL的tyep來命名。這個類一般來說就是一個Bean。例如下面的WSDL:
WSDL2Java將產生下面代碼:
public class Phone implements java.io.Serializable {
public Phone() {...}
public int getAreaCode() {...}
public void setAreaCode(int areaCode) {...}
public java.lang.String getExchange() {...}
public void setExchange(java.lang.String exchange) {...}
public java.lang.String getNumber() {...}
public void setNumber(java.lang.String number) {...}
public boolean equals(Object obj) {...}
public int hashCode() {...}
}
其他元素的映射前面相關部分已經做過介紹。
1.4.3 Java2WSDL:從java程序生成WSDL
第一步:提供一個Java接口或着類。
寫一個java接口或類,編譯這個程序,這裏是一個接口描述一個web服務。
package samples.userguide.example6;
/**
* Interface describing a web service to set and get Widget prices.
**/
public interface WidgetPrice {
public void setWidgetPrice(String widgetName, String price);
public String getWidgetPrice(String widgetName);
}
第二步:使用Java2WSDL生成WSDL
使用Java2WSDL工具從上面的接口生成WSDL。下面是調用這個工具的命令:
% java org.apache.axis.wsdl.Java2WSDL -o wp.wsdl
-l"http://localhost:8080/axis/services/WidgetPrice"
-n "urn:Example6" -p"samples.userguide.example6" "urn:Example6"
samples.userguide.example6.WidgetPrice
這裏:
-o 指定了生成的WSDL文件名稱
-l 指定了服務的位置
-n WSDL文件的target namespace
-p 指定了從包名到namespace的映射
類指定了服務包含的接口。
生成的WSDL文檔將包含相應的WSDL類型,消息,portType,bindings和支持SOAP RPC的服務描述,web服務的編碼。如果你定義的接口方法引用了其他的類,Java2WSDL工具將生成相應的xml類型來替代這個類或任何嵌入或繼承類型。這個工具支持JAX-RPC複雜類型(bean class),xtension classes, enumeration classes, arrays 和Holder classes.。
第三步:使用WSDL2Java創建Bindings
使用生成的WSDL文件爲web服務生成相應的client/server bindings。
% java org.apache.axis.wsdl.WSDL2Java -o . -d Session -s -S true
-Nurn:Example6 samples.userguide.example6 wp.wsdl
這將生成下列文件
現在你擁有了部署服務,建立客戶程序所需要的所有文件了。
注意:程序源代碼 請查看官方網站!