使用axis2進行WebService的開發
Apache Axis2 是 Apache Axis SOAP 項目的後繼項目。此項目是 Web 服務核心引擎的重要改進,目标是成為 Web 服務和面向服務的體系結構(Service-Oriented Architecture,SOA)的下一代平台。
axis2 WebService開發分為服務端開發與用戶端開發,服務端開發為對外提供服務,用戶端開發為使用者調用外部接口進行業務處理。
一、下載下傳與安裝
1.下載下傳
下載下傳位址:http://axis.apache.org/axis2/java/core/download.cgi
有以下下載下傳清單:
Binary Distribution zip | MD5 | PGP
Source Distribution zip | MD5 | PGP
WAR Distribution zip | MD5 | PGP
Documents Distribution zip | MD5 | PGP
注:
axis2-1.6.2-bin.zip裡有axis2的jar包。
axis2-1.6.2-docs.zip裡有詳細的幫助文檔。
axis2-1.6.2-src.zip裡是源代碼。
axis2-1.6.2-war.zip裡是axis的管理平台,放到tomcat可直接使用。
注:本文用bin包進行指令行使用axis2,管理平台使用的是war包。
2.安裝配置
将axis2-1.6.2-bin.zip解壓到本地目錄D:\axis2-1.6.2
設定環境變量。【注:前提需要配置java環境變量】
AXIS2_HOME 設定值 D:\axis2-1.6.2
Path 添加值 %AXIS2_HOME%\bin
二、服務端編寫
1.建立服務端的java項目testAsixServer。
編寫類City與類User代碼如下:
package com.hsinghsu.model;
public class City
{
private int cityCode;
private String cityName;
public int getCityCode()
{
return cityCode;
}
public void setCityCode(int cityCode)
{
this.cityCode = cityCode;
}
public String getCityName()
{
return cityName;
}
public void setCityName(String cityName)
{
this.cityName = cityName;
}
}
package com.hsinghsu.model;
public class User
{
private int id;
private String name;
private String password;
private City city;
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public City getCity()
{
return city;
}
public void setCity(City city)
{
this.city = city;
}
}
編寫服務類UserService。該服務類即為對外提供的服務,其中對外提供2個服務getUserById與getUserList,代碼如下:
package com.hsinghsu.service;
import java.util.ArrayList;
import java.util.List;
import com.hsinghsu.model.User;
public class UserService
{
public List<User> getUserList(User user)
{
List<User> list = new ArrayList<User>();
return list;
}
public User getUserById(int id)
{
User user = new User();
return user;
}
}
2.釋出WebService服務
釋出WebService服務方式可使用axis2管理平台釋出,本文另添加使用soapUI釋出WebService的測試服務。
2.1 axis2管理平台釋出
2.1.1 部署axis2管理平台
将axis2-1.6.1-war.zip壓縮包裡面的axis2.war包解壓到tomcat的webapps目錄下,啟動tomcat,通路位址http://127.0.0.1:8080/axis2/ ,即可通路axis2的Welcome!頁面。
通路位址http://127.0.0.1:8080/axis2/services/listServices 另可通路服務清單。
2.1.2 部署開發服務
編譯服務端項目testAsixServer後,将UserService.class檔案放到tomcat\webapps\axis2\WEB-INF\pojo目錄中【注:若沒有pojo目錄,則手動建立該目錄】。
在浏覽器位址欄中輸入如下的URL:
http://127.0.0.1:8080/axis2/services/listServices 即可通路重新整理後的服務清單。【注:POJO類不能使用package關鍵字聲明包,若使用axis2管理平台釋出,則需要修改UserService類,去掉package字段。】
【注:釋出WebService的pojo目錄隻是預設的,如果想在其他的目錄釋出WebService,可以打開axis2/WEB-INF/conf/axis2.xml檔案,并在<axisconfig>元素中添加如下的子元素:
<deployer extension=".class" directory="mydir" class="org.apache.axis2.deployment.POJODeployer"/>】
通路 http://127.0.0.1:8080/axis2/services/UserService?wsdl 即可通路服務UserService的wsdl描述
【注:另可使用jar cvf指令将服務打成aar包後導入到axis2管理平台上使用。】
2.2 使用soapUI生成WAR釋出WebService測試服務
2.2.1 由java生成wsdl檔案
運用Java2wsdl生成wsdl檔案
使用cmd指令,在指令行中輸入:
java2wsdl -cn com.hsinghsu.service.UserService
【注:在testAsixServer項目的classes根目錄下執行】
輸出:
Using AXIS2_HOME: D:\axis2-1.6.2
Using JAVA_HOME: C:\Program Files\Java\jdk1.6.0_01
log4j:WARN No appenders could be found for logger (org.apache.axis2.util.Loader).
log4j:WARN Please initialize the log4j system properly.
結果:
生成UserService.wsdl檔案
2.2.2 soapUI導出war包:
在soapUI導入UserService.wsdl檔案。
通過soapUI生成MockService。
啟動MockService,測試MockService時,在URL填寫http://HSING-PC:8088/mockUserServiceSoap11Binding 後點選運作,檢視是否有正确封包傳回。
soapUI發送封包如下:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.hsinghsu.com">
<soapenv:Header/>
<soapenv:Body>
<ser:getUserById>
<!--Optional:-->
<ser:id>2</ser:id>
</ser:getUserById>
</soapenv:Body>
</soapenv:Envelope>
soapUI接收封包如下:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.hsinghsu.com" xmlns:xsd="http://model.hsinghsu.com/xsd">
<soapenv:Header/>
<soapenv:Body>
<ser:getUserByIdResponse>
<!--Optional:-->
<ser:return>
<!--Optional:-->
<xsd:city>
<!--Optional:-->
<xsd:cityCode>001</xsd:cityCode>
<!--Optional:-->
<xsd:cityName>wh</xsd:cityName>
</xsd:city>
<!--Optional:-->
<xsd:id>1</xsd:id>
<!--Optional:-->
<xsd:name>hsinghsu</xsd:name>
<!--Optional:-->
<xsd:password>123456</xsd:password>
</ser:return>
</ser:getUserByIdResponse>
</soapenv:Body>
</soapenv:Envelope>
在soapUI中導出war包,如testUser.war。
2.2.3 部署war包
将war包部署到tomcat目錄下。【注:需要修改war包裡面的WEB-INF/soapui/testUser-soapui-project.xml檔案引用wsdl檔案的路徑】
啟動tomcat,通路在war所在的路徑如 http://127.0.0.1:8080/testUser/mockUserServiceSoap11Binding?WSDL ,即可檢視wsdl描述檔案
【注:可以使用soapUI測試接口,在soapUI測試中,URL中填寫testUser.war的部署位址,如http://ip:port/testUser/mockUserServiceSoap11Binding ,點選運作,檢視對應的接口是否有正确封包傳回。】
三、用戶端編寫
Axis2支援以下4種類型的用戶端:
i. Block(阻塞式用戶端),即傳統用戶端。一旦服務被啟用,用戶端的應用程式将被挂起,直到operation被執行完畢(表現為收到一個response或fault),才能重新獲得控制權。這是調用Web Service最簡單的方式,并且這種方式适用于多數業務情形。
ii. Non block(非阻塞式用戶端),即異步用戶端。使用Non-Blocking API來調用這些Web Services。Axis2提供給使用者一種基于回叫機制的non-blocking API,一旦服務被起用,用戶端應用程式馬上得到控制權,通過使用一個callback對象來獲得response。這種方式使得用戶端應用程式可以很友善的同步啟用多個Web Service。
iii.雙工(雙向傳輸)。以上的機制都使用單一的連接配接去發送請求和接收響應.這都明顯在性能上落後于使用兩條連接配接(單向或雙向)進行進行請求和響應的傳輸 . 是以以上的機制都不能解決長時間運作的交易, 連接配接将在操作還沒完成就會逾時. 一種解決方案是使用分開的兩條傳輸連接配接來傳輸請求和響應 . 我們叫這種方案為傳輸層異步。
iv. 雙工非阻塞(雙向且非阻塞傳輸)。
注:axis2 webservice client端需要的jar包有:
axis2-kernel-1.6.1.jar
axis2-adb-1.6.1.jar
axiom-api-1.2.12.jar
commons-logging-1.1.1.jar
wsdl4j-1.6.2.jar
XmlSchema-1.4.7.jar
axiom-impl-1.2.12.jar
neethi-3.0.1.jar
axis2-transport-local-1.6.1.jar
axis2-transport-http-1.6.1.jar
commons-httpclient-3.1.jar
httpcore-4.0.jar
commons-codec-1.3.jar
mail-1.4.jar
1.傳統用戶端【阻塞式用戶端的編寫】
建立AsixBlockClient類,擷取資料,代碼如下:
package com.hsinghsu.asix.client;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
/**
*
* Block(阻塞式用戶端),即傳統用戶端調用WebService Axis2的底層API來調用WebService
*
* @author hsinghsu
*
*/
public class AsixBlockClient
{
private static EndpointReference targetEPR = new EndpointReference(
"http://127.0.0.1:8080/testUser/mockUserServiceSoap11Binding");//接口位址
public static void main(String[] args)
{
Options options = new Options();
options.setAction("urn:getUserById");//調用接口方法
options.setTo(targetEPR);
ServiceClient sender = null;
try
{
sender = new ServiceClient();
sender.setOptions(options);
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace(
"http://service.hsinghsu.com", "");
OMElement method = fac.createOMElement("getUserById", omNs);
OMElement name = fac.createOMElement("id", omNs);//設定入參名稱
name.setText("1");//設定入參值
method.addChild(name);
method.build();
System.out.println("method:" + method.toString());// print:<getUserById xmlns="http://service.hsinghsu.com"><id>1</id></getUserById>
OMElement response = sender.sendReceive(method);
System.out.println("response:" + response);
OMElement elementReturn = response.getFirstElement().getFirstElement().getFirstElement();
System.out.println("cityCode:"+elementReturn.getText());
}
catch (AxisFault e)
{
System.out.println("Error");
e.printStackTrace();
}
}
}
執行結果如下:
method:<getUserById xmlns="http://service.hsinghsu.com"><id>1</id></getUserById>
response:<ser:getUserByIdResponse xmlns:ser="http://service.hsinghsu.com">
<!--Optional:-->
<ser:return>
<!--Optional:-->
<xsd:city xmlns:xsd="http://model.hsinghsu.com/xsd">
<!--Optional:-->
<xsd:cityCode>001</xsd:cityCode>
<!--Optional:-->
<xsd:cityName>wh</xsd:cityName>
</xsd:city>
<!--Optional:-->
<xsd:id xmlns:xsd="http://model.hsinghsu.com/xsd">1</xsd:id>
<!--Optional:-->
<xsd:name xmlns:xsd="http://model.hsinghsu.com/xsd">hsinghsu</xsd:name>
<!--Optional:-->
<xsd:password xmlns:xsd="http://model.hsinghsu.com/xsd">123456</xsd:password>
</ser:return>
</ser:getUserByIdResponse>
cityCode:001
2.使用RPC方法調用WebService
編寫AsixRPCClient.java類,擷取資料。注:添加User.java、City.java至項目中。
AsixRPCClient.java代碼如下:
package com.hsinghsu.asix.client;
import javax.xml.namespace.QName;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.rpc.client.RPCServiceClient;
import com.hsinghsu.model.User;
/**
* 使用RPC方式調用WebService
*
* @author hsinghsu
*
*/
public class AsixRPCClient
{
/**
* @param args
*/
public static void main(String[] args) throws Exception
{
// 使用RPC方式調用WebService
RPCServiceClient serviceClient = new RPCServiceClient();
Options options = serviceClient.getOptions();
EndpointReference targetEPR = new EndpointReference(
"http://127.0.0.1:8080/testUser/mockUserServiceSoap11Binding");// 指定調用WebService的URL
options.setTo(targetEPR);
Object[] opAddEntryArgs = new Object[]{new Integer(1)};// 指定getGreeting方法的參數值
Class[] classes = new Class[]{User.class};// 指定getGreeting方法傳回值的資料類型的Class對象
QName opAddEntry = new QName("http://service.hsinghsu.com",
"getUserById");// 指定要調用的getGreeting方法及WSDL檔案的命名空間
Object[] objects = serviceClient.invokeBlocking(opAddEntry,
opAddEntryArgs, classes);// RPCServiceClient類的invokeBlocking方法調用了WebService中的方法。invokeBlocking方法有三個參數,其中第一個參數的類型是QName對象,表示要調用的方法名;第二個參數表示要調用的WebService方法的參數值,參數類型為Object[];第三個參數表示WebService方法的傳回值類型的Class對象,參數類型為Class[]。當方法沒有參數時,invokeBlocking方法的第二個參數值不能是null,而要使用new Object[]{}。
System.out.println(" objects size-->:" + objects.length);
if (objects.length >= 1)
{
User user = new User();
user = (User) objects[0];
System.out.println("==" + user.getId() + " ==" + user.getName()
+ " ==" + user.getCity().getCityName());
}
}
}
運作結果:
objects size-->:1[Ljava.lang.Object;@ba5c7a
==1 ==hsinghsu ==wh
3.使用Stub方式調用WebService
運用wsdl2java簡化用戶端,使用Stub方式調用WebService
3.1 生成STUB檔案。
在cmd中用 wsdl2java生成stub檔案。注:在wsdl檔案目錄下執行
輸入:
wsdl2java -uri UserService.wsdl
【注:預設adb生成方式,同步生成方式,加參數-a則使用異步生成】
輸出:
Using AXIS2_HOME: D:\axis2-1.6.2
Using JAVA_HOME: C:\Program Files\Java\jdk1.6.0_01
Retrieving document at 'UserService.wsdl'.
log4j:WARN No appenders could be found for logger (org.apache.axis2.description.WSDL11ToAllAxisServicesBuilder).
log4j:WARN Please initialize the log4j system properly.
結果:
生成build.xml、UserServiceStub.java、UserServiceCallbackHandler.java檔案
3.2 編寫同步調用函數
編寫AsixServiceStub類,擷取資料。
AsixServiceStub.java代碼如下:
package com.hsinghsu.asix.client;
import com.hsinghsu.service.UserServiceStub;
import com.hsinghsu.service.UserServiceStub.GetUserById;
import com.hsinghsu.service.UserServiceStub.User;
/**
* 利用axis2插件生成用戶端方式調用 wsdl2java簡化用戶端的編寫
*
* @author hsinghsu
*
*/
public class AsixServiceStub
{
public static void main(String[] args) throws Exception
{
UserServiceStub stub = new UserServiceStub();
GetUserById guid = new GetUserById();
guid.setId(1);
User user = stub.getUserById(guid).get_return();// 同步調用方式
if (null != user)
{
System.out.println("==" + user.getId() + " ==" + user.getName()
+ " ==" + user.getCity().getCityName());
}
else
{
System.out.println("user null");
}
}
}
運作結果:
==1 ==hsinghsu ==wh
注:添加UserServiceStub.java、UserServiceCallbackHandler.java檔案至項目中,注意修改UserServiceStub.java類中服務的位址。
注:若需要使用異步調用,則需建立異步回調類AsynCallback,該類需要繼承UserServiceCallbackHandler抽象類,實作回調函數receiveResultgetUserById接口。在AsixServiceStub中,隻需要使用stub.startgetUserById(guid, new AsynCallback());執行即可。