java axis2 教程_webservice的Axis2入门教程java版
本文轉自百度文庫
Axis2是一套嶄新的WebService引擎,該版本是對Axis1.x重新設計的產物。Axis2不僅支持SOAP1.1和SOAP1.2,還集成了非常流行的REST WebService,同時還支持Spring、JSON等技術。這些都將在后面的系列教程中講解。在本文中主要介紹了如何使用Axis2開發一個不需要任何配置文件的WebService,并在客戶端使用Java和C#調用這個WebService。
一、Axis2的下載和安裝
讀者可以從如下的網址下載Axis2的最新版本:
在本文使用了目前Axis2的最新版本1.4.1。讀者可以下載如下兩個zip包:
axis2-1.4.1-bin.zip
axis2-1.4.1-war.zip
其中axis2-1.4.1-bin.zip文件中包含了Axis2中所有的jar文件, axis2-1.4.1-war.zip文件用于將WebService發布到Web容器中。
將axis2-1.4.1-war.zip文件解壓到相應的目錄,將目錄中的axis2.war文件放到\webapps目錄中(本文使用的Tomcat的版本是6.x),并啟動Tomcat。
在瀏覽器地址欄中輸入如下的URL:
如果在瀏覽器中顯示出如圖1所示的頁面,則表示Axis2安裝成功。
圖1
二、編寫和發布WebService
對于用Java實現的服務程序給人的印象就是需要進行大量的配置,不過這一點在Axis2中將被終結。在Axis2中不需要進行任何的配置,就可以直接將一個簡單的POJO發布成WebService。其中POJO中所有的public方法將被發布成WebService方法。
下面我們來實現一個簡單的POJO,代碼如下:
public classSimpleService
{publicString getGreeting(String name)
{return "你好 " +name;
}public intgetPrice()
{return new java.util.Random().nextInt(1000);
}
}
在SimpleService類中有兩個方法,由于這兩個方法都是public方法,因此,它們都將作為WebService方法被發布。
編譯SimpleService類后,將SimpleService.class文件放到\webapps\axis2\WEB-INF\pojo目錄中(如果沒有pojo目錄,則建立該目錄)。現在我們已經成功將SimpleService類發布成了WebService。在瀏覽器地址欄中輸入如下的URL:
這時當前頁面將顯示所有在Axis2中發布的WebService,如圖2所示。
圖2
在瀏覽器地址欄中輸入如下的兩個URL來分別測試getGreeting和getPrice方法:
圖3和圖4分別顯示了getGreeting和getPrice方法的測試結果。
圖3? getGreeting方法的測試結果
圖4? getPrice方法的測試結果
在編寫、發布和測試0配置的WebService時應注意如下幾點:
1.?POJO類不能使用package關鍵字聲明包。
2.?Axis2在默認情況下可以熱發布WebService,也就是說,將WebService的.class文件復制到pojo目錄中時,Tomcat不需要重新啟動就可以自動發布WebService。如果想取消Axis2的熱發布功能,可以打開\webapps\axis2\WEB-INF\conf\axis2.xml,找到如下的配置代碼:
true
將true改為false即可。要注意的是,Axis2在默認情況下雖然是熱發布,但并不是熱更新,也就是說,一旦成功發布了WebService,再想更新該WebService,就必須重啟Tomcat。這對于開發人員調試WebService非常不方便,因此,在開發WebService時,可以將Axis2設為熱更新。在axis2.xml文件中找到false,將false改為true即可。
3.?在瀏覽器中測試WebService時,如果WebService方法有參數,需要使用URL的請求參數來指定該WebService方法參數的值,請求參數名與方法參數名要一致,例如,要測試getGreeting方法,請求參數名應為name,如上面的URL所示。
4.?發布WebService的pojo目錄只是默認的,如果讀者想在其他的目錄發布WebService,可以打開axis2.xml文件,并在元素中添加如下的子元素:
上面的配置允許在\webapps\axis2\WEB-INF\my目錄中發布WebService。例如,將本例中的SimpleService.class復制到my目錄中也可以成功發布(但要刪除pojo目錄中的SimpleService.class,否則WebService會重名)。
三、用Java實現調用WebService的客戶端程序
WebService是為程序服務的,只在瀏覽器中訪問WebService是沒有意義的。因此,在本節使用Java實現了一個控制臺程序來調用上一節發布的WebService。調用WebService的客戶端代碼如下:
packageclient;importjavax.xml.namespace.QName;importorg.apache.axis2.addressing.EndpointReference;importorg.apache.axis2.client.Options;importorg.apache.axis2.rpc.client.RPCServiceClient;public classRPCClient
{public static void main(String[] args) throwsException
{//使用RPC方式調用WebService
RPCServiceClient serviceClient = newRPCServiceClient();
Options options=serviceClient.getOptions();//指定調用WebService的URL
EndpointReference targetEPR = newEndpointReference("http://localhost:8080/axis2/services/SimpleService");
options.setTo(targetEPR);//指定getGreeting方法的參數值
Object[] opAddEntryArgs = new Object[] {"超人"};//指定getGreeting方法返回值的數據類型的Class對象
Class[] classes = new Class[] {String.class};//指定要調用的getGreeting方法及WSDL文件的命名空間
QName opAddEntry = new QName("http://ws.apache.org/axis2", "getGreeting");//調用getGreeting方法并輸出該方法的返回值
System.out.println(serviceClient.invokeBlocking(opAddEntry, opAddEntryArgs, classes)[0]);//下面是調用getPrice方法的代碼,這些代碼與調用getGreeting方法的代碼類似
classes = new Class[] {int.class};
opAddEntry= new QName("http://ws.apache.org/axis2", "getPrice");
System.out.println(serviceClient.invokeBlocking(opAddEntry,new Object[]{}, classes)[0]);
}
}
運行上面的程序后,將在控制臺輸出如下的信息:
你好?超人
443
在編寫客戶端代碼時應注意如下幾點:
1.?客戶端代碼需要引用很多Axis2的jar包,如果讀者不太清楚要引用哪個jar包,可以在Eclipse的工程中引用Axis2發行包的lib目錄中的所有jar包。
2.?在本例中使用了RPCServiceClient類的invokeBlocking方法調用了WebService中的方法。invokeBlocking方法有三個參數,其中第一個參數的類型是QName對象,表示要調用的方法名;第二個參數表示要調用的WebService方法的參數值,參數類型為Object[];第三個參數表示WebService方法的返回值類型的Class對象,參數類型為Class[]。當方法沒有參數時,invokeBlocking方法的第二個參數值不能是null,而要使用new Object[]{}。
3.?如果被調用的WebService方法沒有返回值,應使用RPCServiceClient類的invokeRobust方法,該方法只有兩個參數,它們的含義與invokeBlocking方法的前兩個參數的含義相同。
4.?在創建QName對象時,QName類的構造方法的第一個參數表示WSDL文件的命名空間名,也就是元素的targetNamespace屬性值,下面是SimpleService類生成的WSDL文件的代碼片段:
四、用wsdl2java簡化客戶端的編寫
也許有很多讀者會說“有沒有搞錯啊,只調用兩個WebService方法用要寫這么多代碼,太麻煩了”。
不過幸好Axis2提供了一個wsdl2java.bat命令可以根據WSDL文件自動產生調用WebService的代碼。wsdl2java.bat命令可以在"bin目錄中找到。在使用wsdl2java.bat命令之前需要設置AXIS2_HOME環境變量,該變量值是。
在Windows控制臺輸出如下的命令行來生成調用WebService的代碼:
%AXIS2_HOME%\bin\wsdl2java -uri http://localhost:8080/axis2/services/SimpleService?wsdl -p com.jlins.client -s -o stub
其中-url參數指定了wsdl文件的路徑,可以是本地路徑,也可以是網絡路徑。-p參數指定了生成的Java類的包名,-o參數指定了生成的一系列文件保存的根目錄。在執行完上面的命令后,讀者就會發現在當前目錄下多了個stub目錄,在."stub"src"client目錄可以找到一個SimpleServiceStub.java文件,該文件復雜調用WebService,讀者可以在程序中直接使用這個類,代碼如下:
packageclient;importjavax.xml.namespace.QName;importorg.apache.axis2.addressing.EndpointReference;importorg.apache.axis2.client.Options;importorg.apache.axis2.rpc.client.RPCServiceClient;public classStubClient
{public static void main(String[] args) throwsException
{
SimpleServiceStub stub= newSimpleServiceStub();
SimpleServiceStub.GetGreeting gg= newSimpleServiceStub.GetGreeting();
gg.setName("比爾");
System.out.println( stub.getGreeting(gg).get_return());
System.out.println(stub.getPrice().get_return());
}
}
上面的代碼大大簡化了調用WebService的步驟,并使代碼更加簡潔。但要注意的是,wsdl2java.bat命令生成的Stub類將WebService方法的參數都封裝在了相應的類中,類名為方法名,例如,getGreeting方法的參數都封裝在了GetGreeting類中,要想調用getGreeting方法,必須先創建GetGreeting類的對象實例。
五、使用C#調用WebService
從理論上說,WebService可以被任何支持SOAP協議的語言調用。在Visual Studio中使用C#調用WebService是在所有語言中最容易實現的(VB.net的調用方法類似,也同樣很簡單)。
新建一個Visual Studio工程,并在引用Web服務的對話框中輸入如下的URL,并輸入Web引用名為“WebService”:
然后引用Web服務的對話框就會顯示該WebService中的所有的方法,如圖5所示。
圖5
在完成上面的工作后,只需要如下三行C#代碼就可以調用getGreeting和getPrice方法,并顯示這兩個方法的返回值:
WebService.SimpleService simpleService = newWSC.WebService.SimpleService();
MessageBox.Show( simpleService.getGreeting("比爾"));
MessageBox.Show(simpleService.getPrice().@return.ToString());
在.net解析WSDL文件時直接將getGreeting方法的參數映射為String類型,因此,可以直接進行傳值。
從上面的調用過程可以看出,添加Web引用的過程就相當于在Java中調用wsdl2java.bat自動生成stub類的過程。只是在調用stub類時與C#有一定的區別,但從總體上來說,都大大簡化了調用WebService的過程。
在實際的應用中,不僅需要使用WebService來傳遞簡單類型的數據,有時也需要傳遞更復雜的數據,這些數據可以被稱為復合類型的數據。數組與類(接口)是比較常用的復合類型。在Axis2中可以直接使用將WebService方法的參數或返回值類型聲明成數組或類(接口)。但要注意,在定義數組類型時只能使用一維數組,如果想傳遞多維數組,可以使用分隔符進行分隔,如下面的代碼所示:
String[] strArray = new String[]{ "自行車,飛機,火箭","中國,美國,德國", "超人,蜘蛛俠,鋼鐵俠" } ;
上面的代碼可以看作是一個3*3的二維數組。
在傳遞類的對象實例時,除了直接將數組類型聲明成相應的類或接口,也可以將對象實例進行序列化,也就是說,將一個對象實例轉換成字節數組進行傳遞,然后接收方再進行反序列化,還原這個對象實例。
下面的示例代碼演示了如何傳遞數組與類(接口)類型的數據,并演示如何使用字節數組上傳圖像。本示例的客戶端代碼使用Java和C#編寫。要完成這個例子需要如下幾步:
一、實現服務端代碼
ComplexTypeService是一個WebService類,該類的代碼如下:
importjava.io.FileOutputStream;importdata.DataForm;public classComplexTypeService
{//上傳圖像,imageByte參數表示上傳圖像文件的字節,//length參數表示圖像文件的字節長度(該參數值可能小于imageByte的數組長度)
public boolean uploadImageWithByte(byte[] imageByte, intlength)
{
FileOutputStream fos= null;try{//將上傳的圖像保存在D盤的test1.jpg文件中
fos = new FileOutputStream("d:\\test1.jpg");//開始寫入圖像文件的字節
fos.write(imageByte, 0, length);
fos.close();
}catch(Exception e)
{return false;
}finally{if (fos != null)
{try{
fos.close();
}catch(Exception e)
{
}
}
}return true;
}//返回一維字符串數組
publicString[] getArray()
{
String[] strArray= new String[]{ "自行車", "飛機", "火箭"};returnstrArray;
}//返回二維字符串數組
publicString[] getMDArray()
{
String[] strArray= new String[]{ "自行車,飛機,火箭","中國,美國,德國", "超人,蜘蛛俠,鋼鐵俠"} ;returnstrArray;
}//返回DataForm類的對象實例
publicDataForm getDataForm()
{return newDataForm();
}//將DataForm類的對象實例序列化,并返回序列化后的字節數組
public byte[] getDataFormBytes() throwsException
{
java.io.ByteArrayOutputStream baos= newjava.io.ByteArrayOutputStream();
java.io.ObjectOutputStream oos= newjava.io.ObjectOutputStream(baos);
oos.writeObject(newDataForm());returnbaos.toByteArray();
}
}
二、實現DataForm類
DataForm是要返回的對象實例所對應的類,該類的實現代碼如下:
packagedata;public class DataForm implementsjava.io.Serializable
{private String name = "bill";private int age = 20;publicString getName()
{returnname;
}public voidsetName(String name)
{this.name =name;
}public intgetAge()
{returnage;
}public void setAge(intage)
{this.age =age;
}
}
三、發布WebService
由于本示例的WebService類使用了一個Java類(DataForm類),因此,在發布WebService之前,需要先將DataForm.class文件復制到\webapps\axis2\WEB-INF\classes\data目錄中,然后將ComplexTypeService.class文件復制到\webapps\axis2\WEB-INF\pojo目錄中,最后啟動Tomcat(如果Tomcat已經啟動,由于增加了一個DataForm類,因此,需要重新啟動Tomcat)。
四、使用Java編寫調用WebService的客戶端代碼
在客戶端仍然使用了RPC的調用方式,代碼如下:
packageclient;importjavax.xml.namespace.QName;importorg.apache.axis2.addressing.EndpointReference;importorg.apache.axis2.client.Options;importorg.apache.axis2.rpc.client.RPCServiceClient;public classComplexTypeRPCClient
{public static void main(String[] args) throwsException
{
RPCServiceClient serviceClient= newRPCServiceClient();
Options options=serviceClient.getOptions();
EndpointReference targetEPR= newEndpointReference("http://localhost:8080/axis2/services/ComplexTypeService");
options.setTo(targetEPR);//下面的代碼調用uploadImageWithByte方法上傳圖像文件
///打開圖像文件,確定圖像文件的大小
java.io.File file = new java.io.File("f:\\images.jpg");
java.io.FileInputStream fis= new java.io.FileInputStream("f:\\images.jpg");//創建保存要上傳的圖像文件內容的字節數組
byte[] buffer = new byte[(int) file.length()];//將圖像文件的內容讀取buffer數組中
int n =fis.read(buffer);
System.out.println("文件長度:" +file.length());
Object[] opAddEntryArgs= newObject[]{ buffer, n };
Class[] classes= new Class[]{ Boolean.class};
QName opAddEntry= new QName("http://ws.apache.org/axis2","uploadImageWithByte");
fis.close();//開始上傳圖像文件,并輸出uploadImageWithByte方法的返回傳
System.out.println(serviceClient.invokeBlocking(opAddEntry,opAddEntryArgs, classes)[0]);///下面的代碼調用了getArray方法,并返回一維String數組
/
opAddEntry = new QName("http://ws.apache.org/axis2", "getArray");
String[] strArray=(String[]) serviceClient.invokeBlocking(opAddEntry,new Object[]{}, new Class[]{String[].class })[0];for(String s : strArray)
System.out.print(s+ " ");
System.out.println();///下面的代碼調用了getMDArray方法,并返回一維String數組
/
opAddEntry = new QName("http://ws.apache.org/axis2", "getMDArray");
strArray= (String[]) serviceClient.invokeBlocking(opAddEntry, newObject[]{},new Class[]{String[].class})[0];for(String s : strArray)
{
String[] array= s.split(",");for(String ss: array)
System.out.print(" ");
System.out.println();
}
System.out.println();///下面的代碼調用了getDataForm方法,并返回DataForm對象實例
/
opAddEntry = new QName("http://ws.apache.org/axis2", "getDataForm");
data.DataForm df= (data.DataForm) serviceClient.invokeBlocking(opAddEntry, newObject[]{},new Class[]{data.DataForm.class})[0];
System.out.println(df.getAge());///下面的代碼調用了getDataFormBytes方法,并返回字節數組,最后將返回的字節數組反序列化后,轉換成DataForm對象實例
/
opAddEntry = new QName("http://ws.apache.org/axis2", "getDataFormBytes");
buffer= (byte[]) serviceClient.invokeBlocking(opAddEntry, new Object[]{}, new Class[]{byte[].class})[0];
java.io.ObjectInputStream ois= newjava.io.ObjectInputStream(newjava.io.ByteArrayInputStream(buffer));
df=(data.DataForm) ois.readObject();
System.out.println(df.getName());//}
}
運行上面的程序,將輸出如下的內容:
文件長度:3617
true
自行車?飛機?火箭
20
bill
五、使用C#編寫調用WebService的客戶端代碼
在Visual Studio中使用WebService就簡單得多。假設引用WebService時的引用名為complexType,則下面的代碼調用了uploadImageWithByte方法來上傳圖像文件。在Visual Studio引用WebService時,uploadImageWithByte方法多了兩個out參數,在使用時要注意。
complexType.ComplexTypeService cts = newWSC.complexType.ComplexTypeService();
System.IO.FileStream fs= new System.IO.FileStream(@"f:\images.jpg", System.IO.FileMode.Open);byte[] buffer = new byte[fs.Length];
fs.Read(buffer,0, (int)fs.Length);
bool r;
bool rs;
cts.uploadImageWithByte( buffer, (int)fs.Length, true, out r, out rs);
在獲得二維數組時,可以將數據加載到DataGridView或其他類似的控件中,代碼如下:
String[] strArray =cts.getMDArray();for (int i = 0; i < strArray.Length; i++)
{//用正則表達式將帶分隔符的字符串轉換成String數組
String[] columns = strArray[i].Split(',');//如果DataGridView的表頭不存在,向DataGridView控件添加三個帶表頭的列
if (dataGridView1.Columns.Count == 0)for (int j = 0; j < columns.Length; j++)
dataGridView1.Columns.Add("column" + (j + 1).ToString(), "列" + (j + 1).ToString());//添加行
dataGridView1.Rows.Add(1);for(int j = 0; j < columns.Length; j++)
{
dataGridView1.Rows[i].Cells[j].Value=columns[j];
}
}
向DataGridView控件添加數據后的效果如圖1所示。
圖1
對于其他的WebService方法的調用都非常簡單,讀者可以自己做這個實驗。
要注意的是,由于.net和java序列化和反序列化的差異,通過序列化的方式傳遞對象實例只使用于客戶端與服務端為同一種語言或技術的情況,如客戶端和服務端都使用Java來編寫。
如果讀者要上傳大文件,應盡量使用FTP的方式來傳遞,而只通過WebService方法來傳遞文件名等信息。這樣有助于提高傳輸效率。
下一篇:WebService大講堂之Axis2(3):使用services.xml文件發布WebService
用Axis2實現Web Service,雖然可以將POJO類放在axis2\WEB-INF\pojo目錄中直接發布成Web Service,這樣做不需要進行任何配置,但這些POJO類不能在任何包中。這似乎有些不方便,為此,Axis2也允許將帶包的POJO類發布成Web Service。
先實現一個POJO類,代碼如下:
packageservice;public classMyService
{publicString getGreeting(String name)
{return "您好 " +name;
}public voidupdate(String data)
{
System.out.println("已經更新");
}
}
這個類有兩個方法,這兩個方法都需要發布成Web Service方法。這種方式和直接放在pojo目錄中的POJO類不同。要想將MyService類發布成Web Service,需要一個services.xml文件,這個文件需要放在META-INF目錄中,該文件的內容如下:
Web Service例子
service.MyService
其中元素用于發布Web Service,一個元素只能發布一個WebService類,name屬性表示WebService名,如下面的URL可以獲得這個WebService的WSDL內容:
其中name屬性名就是上面URL中"?"和"/"之間的部分。
元素表示當前Web Service的描述,元素用于設置WebService的參數,在這里用于設置WebService對應的類名。在這里最值得注意的是元素,該元素用于設置處理WebService方法的處理器。例如,getGreeting方法有一個返回值,因此,需要使用可處理輸入輸出的RPCMessageReceiver類,而update方法沒有返回值,因此,需要使用只能處理輸入的RPCInOnlyMessageReceiver類。
使用這種方式發布WebService,必須打包成.aar文件,..aar文件實際上就是改變了擴展名的.jar文件。在現在建立了兩個文件:MyService.java和services.xml。將MyService.java編譯,生成MyService.class。services.xml和MyService.class文件的位置如下:
D:\ws\service\MyService.class
D:\ws\META-INF\services.xml
在windows控制臺中進入ws目錄,并輸入如下的命令生成.aar文件(實際上,.jar文件也可以發布webservice,但axis2官方文檔中建議使用.aar文件發布webservice):
jar cvf ws.aar .
最后將ws.aar文件復制到\webapps\axis2\WEB-INF\services目錄中,啟動Tomcat后,就可以調用這個WebService了。調用的方法和《WebService大講堂之Axis2(1):用POJO實現0配置的WebService》所講的方法類似。
另外services.xml文件中也可以直接指定WebService類的方法,如可以用下面的配置代碼來發布WebService:
Web Service例子
service.MyService
上面的配置代碼前面的部分和以前的services.xml文件的內容相同,但后面使用了元素來指定每一個WebService方法,并單獨指定了處理每一個方法的處理器。對于客戶端來說,調用使用這兩個services.xml文件發布的WebService并沒有太大我區別,只是使用第二個services.xml文件發布WebServices后,在使用wsdl2java命令或使用C#、delphi等生成客戶端的stub時,update方法的String類型被封裝在了update類中,在傳遞update方法的參數時需要建立update類的對象實例。而使用第一個services.xml文件發布的WebService在生成stub時直接可以為update方法傳遞String類型的參數。從這一點可以看出,這兩種方法生成的WSDL有一定的區別。但實際上,如果客戶端程序使用第一個services.xml文件發布的WebService生成stub類時(這時update方法的參數是String),在服務端又改為第二個services.xml文件來發布WebService,這時客戶端并不需要再重新生成stub類,而可以直接調用update方法。也就是說,服務端使用什么樣的方式發布WebService,對客戶端并沒有影響。
如果想發布多個WebService,可以使用元素,如再建立一個MyService1類,代碼如下:
packageservicepublic classMyService1
{publicString getName()
{return "bill";
}
}
在services.xml文件中可以使用如下的配置代碼來配置MyService和MyService1類:
Web Service例子
service.MyService
Web Service例子
service.MyService1
在《WebService大講堂之Axis2(2):復合類型數據的傳遞》中講過,如果要傳遞二進制文件(如圖像、音頻文件等),可以使用byte[]作為數據類型進行傳遞,然后客戶端使用RPC方式進行調用。這樣做只是其中的一種方法,除此之外,在客戶端還可以使用wsdl2java命令生成相應的stub類來調用WebService,wsdl2java命令的用法詳見《WebService大講堂之Axis2(1):用POJO實現0配置的WebService》。
WebService類中包含byte[]類型參數的方法在wsdl2java生成的stub類中對應的數據類型不再是byte[]類型,而是javax.activation.DataHandler。DataHandler類是專門用來映射WebService二進制類型的。
在WebService類中除了可以使用byte[]作為傳輸二進制的數據類型外,也可以使用javax.activation.DataHandler作為數據類型。不管是使用byte[],還是使用javax.activation.DataHandler作為WebService方法的數據類型,使用wsdl2java命令生成的stub類中相應方法的類型都是javax.activation.DataHandler。而象使用.net、delphi生成的stub類的相應方法類型都是byte[]。這是由于javax.activation.DataHandler類是Java特有的,對于其他語言和技術來說,并不認識javax.activation.DataHandler類,因此,也只有使用最原始的byte[]了。
下面是一個上傳二進制文件的例子,WebService類的代碼如下:
packageservice;importjava.io.InputStream;importjava.io.OutputStream;importjava.io.FileOutputStream;importjavax.activation.DataHandler;public classFileService
{//使用byte[]類型參數上傳二進制文件
public boolean uploadWithByte(byte[] file, String filename)
{
FileOutputStream fos= null;try{
fos= newFileOutputStream(filename);
fos.write(file);
fos.close();
}catch(Exception e)
{return false;
}finally{if (fos != null)
{try{
fos.close();
}catch(Exception e)
{
}
}
}return true;
}private void writeInputStreamToFile(InputStream is, OutputStream os) throwsException
{int n = 0;byte[] buffer = new byte[8192];while((n = is.read(buffer)) > 0)
{
os.write(buffer,0, n);
}
}//使用DataHandler類型參數上傳文件
public booleanuploadWithDataHandler(DataHandler file, String filename)
{
FileOutputStream fos= null;try{
fos= newFileOutputStream(filename);//可通過DataHandler類的getInputStream方法讀取上傳數據
writeInputStreamToFile(file.getInputStream(), fos);
fos.close();
}catch(Exception e)
{return false;
}finally{if (fos != null)
{try{
fos.close();
}catch(Exception e)
{
}
}
}return true;
}
}
上面代碼在services.xml文件的配置代碼如下:
文件服務
service.FileService
如果使用wsdl2java命令生成調用Java客戶端代碼,則需要創建DataHandler類的對象實例,代碼如下:
DataHandler dh = new DataHandler(new FileDataSource(imagePath));
wsdl2java命令會為每一個方法生成一個封裝方法參數的類,類名為方法名(第一個字符大寫),如uploadWithByte方法生成的類名為UploadWithByte。如果要設置file參數的值,可以使用UploadWithByte類的setFile方法,代碼如下:
UploadWithByte uwb = newUPloadWithByte();
uwb.setFile(dh);
最后是調用uploadWithByte方法,代碼如下(FileServiceStub為wsdl2java生成的stub類名):
FileServiceStub fss = newFileServiceStub();
fss.uploadWithByte(uwb);
如果使用C#調用FileService,則file參數類型均為byte[],代碼如下:
MemoryStream ms = newMemoryStream();
Bitmap bitmap= newBitmap(picUpdateImage.Image);
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
service.fileService fs= newWSC.service.fileService();
fs.uploadWithDataHandler(ms.ToArray());
fs.uploadWithByte(ms.ToArray());
WebService給人最直觀的感覺就是由一個個方法組成,并在客戶端通過SOAP協議調用這些方法。這些方法可能有返回值,也可能沒有返回值。雖然這樣可以完成一些工具,但這些被調用的方法是孤立的,當一個方法被調用后,在其他的方法中無法獲得這個方法調用后的狀態,也就是說無法保留狀態。
讀者可以想象,這對于一個完整的應用程序,無法保留狀態,就意味著只依靠WebService很難完成全部的工作。例如,一個完整的應用系統都需要進行登錄,這在Web應用中使用Session來保存用戶登錄狀態,而如果用WebService的方法來進行登錄處理,無法保存登錄狀態是非常令人尷尬的。當然,這也可以通過其他的方法來解決,如在服務端使用static變量來保存用戶狀態,并發送一個id到客戶端,通過在服務端和客戶端傳遞這個id來取得相應的用戶狀態。這非常類似于Web應用中通過Session和Cookie來管理用戶狀態。但這就需要由開發人員做很多工作,不過幸好Axis2為我們提供了WebService狀態管理的功能。
使用Axis2來管理WebService的狀態基本上對于開發人員是透明的。在WebService類需要使用org.apache.axis2.context.MessageContext和org.apache.axis2.context.ServiceContext類來保存與獲得保存在服務端的狀態信息,這有些象使用HttpSession接口的getAttribute和setAttribute方法獲得與設置Session域屬性。
除此之外,還需要修改services.xml文件的內容,為元素加一個scope屬性,該屬性有四個可取的值:Application, SOAPSession, TransportSession, Request,不過要注意一下,雖然Axis2的官方文檔將這四個值的單詞首字母和縮寫字母都寫成了大寫,但經筆者測試,必須全部小寫才有效,也就是這四個值應為:application、soapsession、transportsession、request,其中request為scope屬性的默認值。讀者可以選擇使用transportsession和application分別實現同一個WebService類和跨WebService類的會話管理。
在客戶端需要使用setManageSession(true)打開Session管理功能。
綜上所述,實現同一個WebService的Session管理需要如下三步:
1.?使用MessageContext和ServiceContext獲得與設置key-value對。
2.?為要進行Session管理的WebService類所對應的元素添加一個scope屬性,并將該屬性值設為transportsession。
3.?在客戶端使用setManageSession(true)打開Session管理功能。
下面是一個在同一個WebService類中管理Session的例子。
先建立一個WebService類,代碼如下:
packageservice;importorg.apache.axis2.context.ServiceContext;importorg.apache.axis2.context.MessageContext;public classLoginService
{public booleanlogin(String username, String password)
{if("bill".equals(username) && "1234".equals(password))
{//第1步:設置key-value對
MessageContext mc =MessageContext.getCurrentMessageContext();
ServiceContext sc=mc.getServiceContext();
sc.setProperty("login", "成功登錄");return true;
}else{return false;
}
}publicString getLoginMsg()
{//第1步:獲得key-value對中的value
MessageContext mc =MessageContext.getCurrentMessageContext();
ServiceContext sc=mc.getServiceContext();return (String)sc.getProperty("login");
}
}
在LoginService類中有兩個方法:login和getLoginMsg,如果login方法登錄成功,會將“成功登錄”字符串保存在ServiceContext對象中。如果在login方法返回true后調用getLoginMsg方法,就會返回“成功登錄”。
下面是LoginService類的配置代碼(services.xml):
登錄服務
service.LoginService
使用如下的命令生成客戶端使用的stub類:
%AXIS2_HOME%\bin\wsdl2java?-uri?http://localhost:8080/axis2/services/loginService?wsdl?-p?client?-s?-o?stub
在stub\src\client目錄中生成了一個LoginServiceStub.java類,在該類中找到如下的構造句方法:
publicLoginServiceStub(org.apache.axis2.context.ConfigurationContext configurationContext,
java.lang.String targetEndpoint,booleanuseSeparateListener)throwsorg.apache.axis2.AxisFault
{
_serviceClient.getOptions().setSoapVersionURI(
org.apache.axiom.soap.SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI);
}
在該方法中最后添加如下的代碼:
//??第3步:打開客戶端的Session管理功能
_serviceClient.getOptions().setManageSession(true);
下面的客戶端代碼使用LoginServiceStub對象訪問了剛才建立的WebService:
LoginServiceStub stub = newLoginServiceStub();
LoginServiceStub.Login login= newLoginServiceStub.Login();
login.setUsername("bill");
login.setPassword("1234");if(stub.login(login).local_return)
{
System.out.println(stub.getLoginMsg().local_return);
}
運行上面的代碼后,會輸出“成功登錄”信息。
在《WebService大講堂之Axis2(5):會話(Session)管理》一文中介紹了如何使用Axis2來管理同一個服務的會話,但對于一個復雜的系統,不可能只有一個WebService服務,例如,至少會有一個管理用戶的WebService(用戶登錄和注冊)以及處理業務的WebService。象這種情況,就必須在多個WebService服務之間共享會話狀態,也稱為跨服務會話(Session)管理。實現跨服務會話管理與實現同一個服務的會話管理的步驟類似,但仍然有一些差別,實現跨服務會話管理的步驟如下:
實現跨服務的Session管理需要如下三步:
1.?使用MessageContext和ServiceGroupContext獲得與設置key-value對。
2.?為要進行Session管理的WebService類所對應的元素添加一個scope屬性,并將該屬性值設為application。
3.?在客戶端使用setManageSession(true)打開Session管理功能。
從上面的步驟可以看出,實現跨服務會話管理與實現同一個服務的會話管理在前兩步上存在著差異,而第3步是完全一樣的。下面是一個跨服務的會話管理的實例。在這個例子中有兩個WebService類:LoginService和SearchService,代碼如下:LoginService.java
packageservice;importorg.apache.axis2.context.MessageContext;importorg.apache.axis2.context.ServiceGroupContext;public classLoginService
{public booleanlogin(String username, String password)
{if("bill".equals(username) && "1234".equals(password))
{//第1步:設置key-value對
MessageContext mc =MessageContext.getCurrentMessageContext();
ServiceGroupContext sgc=mc.getServiceGroupContext();
sgc.setProperty("login", "成功登錄");return true;
}else{return false;
}
}publicString getLoginMsg()
{//第1步:獲得key-value對中的value
MessageContext mc =MessageContext.getCurrentMessageContext();
ServiceGroupContext sgc=mc.getServiceGroupContext();return (String)sgc.getProperty("login");
}
}
SearchService.java
packageservice;importorg.apache.axis2.context.MessageContext;importorg.apache.axis2.context.ServiceGroupContext;public classSearchService
{publicString findByName(String name)
{//第1步:獲得key-value對中的value
MessageContext mc =MessageContext.getCurrentMessageContext();
ServiceGroupContext sgc=mc.getServiceGroupContext();if (sgc.getProperty("login") != null)return "找到的數據";else
return "用戶未登錄";
}
}
services.xml文件中的配置代碼如下:
登錄服務
service.LoginService
搜索服務
service.SearchService
下面是使用兩個stub類的對象實例訪問上面實現的兩個WebService的客戶端代碼:
LoginServiceStub stub = newLoginServiceStub();
LoginServiceStub.Login login= newLoginServiceStub.Login();
login.setUsername("bill");
login.setPassword("1234");if(stub.login(login).local_return)
{
System.out.println(stub.getLoginMsg().local_return);
SearchServiceStub searchStub= newSearchServiceStub();
SearchServiceStub.FindByName fbn= newSearchServiceStub.FindByName();
fbn.setName("abc");
System.out.println(searchStub.findByName(fbn).local_return);
}
在執行上面的代碼后,將輸出如下的信息:
成功登錄
找到的數據
讀者可以將scope屬性值改成transportsession,看看會輸出什么!
實際上,Axis2的會話管理也是通過Cookie實現的,與Web應用中的Session管理類似。如果讀者使用C#訪問支持會話(在同一個服務中的會話管理)的WebService,需要指定一個CookieContainer對象,代碼如下:
service.loginService ls = newservice.loginService();
System.Net.CookieContainer cc= newSystem.Net.CookieContainer();
ls.CookieContainer=cc;
bool r, rs;
ls.login("bill", "1234", out @r, out rs);if(r)
{
MessageBox.Show(ls.getLoginMsg().@return);
}
如果是訪問跨服務的支持會話的WebService,則不需要指定CookieContainer對象,代碼如下:
service.loginService ls = newservice.loginService();
bool r, rs;
ls.login("bill", "1234", out @r, out rs);if(r)
{
service1.searchService ss= newservice1.searchService();
MessageBox.Show(ss.findByName("abc"));
}
如果讀者使用delphi(本文使用的是delphi2009,其他的delphi版本請讀者自行測試)調用支持會話的WebService時有一些差別。經筆者測試,使用delphi調用WebService,將scope屬性值設為transportsession和application都可以實現跨服務的會話管理,這一點和Java與C#不同,Java和C#必須將scope屬性值設為application才支持跨服務會話管理。在delphi中不需要象C#指定一個CookieContainer或其他類似的對象,而只需要象訪問普通的WebService一樣訪問支持會話的WebService即可。
在現今的Web應用中經常使用Spring框架來裝載JavaBean。如果要想將某些在Spring中裝配的JavaBean發布成WebService,使用Axis2的Spring感知功能是非常容易做到的。
在本文的例子中,除了\webapps\axis2目錄及該目錄中的相關庫外,還需要Spring框架中的spring.jar文件,將該文件復制到\webapps\axis2\WEB-INF\lib目錄中。
下面先建立一個JavaBean(該JavaBean最終要被發布成WebService),代碼如下:
packageservice;importentity.Person;public classSpringService
{privateString name;privateString job;public voidsetName(String name)
{this.name =name;
}public voidsetJob(String job)
{this.job =job;
}publicPerson getPerson()
{
Person person= newPerson();
person.setName(name);
person.setJob(job);returnperson;
}publicString getGreeting(String name)
{return "hello " +name;
}
}
其中Person也是一個JavaBean,代碼如下:
packageentity;public classPerson
{privateString name;privateString job;publicString getName()
{returnname;
}public voidsetName(String name)
{this.name =name;
}publicString getJob()
{returnjob;
}public voidsetJob(String job)
{this.job =job;
}
}
將上面兩個Java源文件編譯后,放到\webapps\axis2\WEB-INF\classes目錄中。
在\webapps\axis2\WEB-INF\web.xml文件中加入下面的內容:
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
/WEB-INF/applicationContext.xml
在\webapps\axis2\WEB-INF目錄中建立一個applicationContext.xml文件,該文件是Spring框架用于裝配JavaBean的配置文件,內容如下:
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
在applicationContext.xml文件中裝配了service.SpringService類,并被始化了name和job屬性。在配置完SpringService類后,就可以直接在程序中FileSystemXmlApplicationContext類或其他類似功能的類讀取applicationContext.xml文件中的內容,并獲得SpringService類的對象實例。但現在我們并不這樣做,而是將SpringService類發布成WebService。
在\webapps\axis2\WEB-INF\lib目錄中有一個axis2-spring-1.4.1.jar文件,該文件用于將被裝配JavaBean的發布成WebService。在D盤建立一個axi2-spring-ws目錄,并在該目錄中建立一個META-INF子目錄。在META-INF目錄中建立一個services.xml文件,內容如下:
Spring aware
org.apache.axis2.extensions.spring.receivers.SpringServletContextObjectSupplier
springService
在Windows控制臺進入axi2-spring-ws目錄,并使用jar命令將axi2-spring-ws目錄中的內容打包成axi2-spring-ws.aar,然后將該文件復制到\webapps\axis2\WEB-INF\services目錄中,啟動Tomcat后,就可以訪問該WebService了,訪問方式與前面幾篇文章的訪問方式相同。獲得wsdl內容的URL如下:
http://localhost:8080/axis2/services/springService?wsdl
在將Spring中的裝配JavaBean發布成WebService需要注意以下幾點:
1.?由JavaBean編譯生成的.class文件需要放在WEB-INF\classes目錄中,或打成.jar包后放在WEB-INF\lib目錄中,而WEB-INF\services目錄中的.aar包中不需要包含.class文件,而只需要包含一個META-INF目錄,并在該目錄中包含一個services.xml文件即可。
2.?services.xml的配置方法與前幾篇文章的配置方法類似,只是并不需要使用ServiceClass參數指定要發布成WebService的Java類,而是要指定在applicationContext.xml文件中的裝配JavaBean的名稱(SpringBeanName參數)。
3.?在services.xml文件中需要通過ServiceObjectSupplier參數指定SpringServletContextObjectSupplier類來獲得Spring的ApplicationContext對象。
在前面幾篇文章中都是使用同步方式來調用WebService。也就是說,如果被調用的WebService方法長時間不返回,客戶端將一直被阻塞,直到該方法返回為止。使用同步方法來調用WebService雖然很直觀,但當WebService方法由于各種原因需要很長時間才能返回的話,就會使客戶端程序一直處于等待狀態,這樣用戶是無法忍受的。
當然,我們很容易就可以想到解決問題的方法,這就是多線程。解決問題的基本方法是將訪問WebService的任務交由一個或多個線程來完成,而主線程并不負責訪問WebService。這樣即使被訪問的WebService方法長時間不返回,客戶端仍然可以做其他的工作。我們可以管這種通過多線程訪問WebService的方式稱為異步訪問。
雖然直接使用多線程可以很好地解決這個問題,但比較麻煩。幸好Axis2的客戶端提供了異步訪問WebService的功能。
RPCServiceClient類提供了一個invokeNonBlocking方法可以通過異步的方式來訪問WebService。下面先來建立一個WebService。
MyService是一個WebService類,代碼如下:
packageservice;public classMyService
{publicString getName()
{try{
System.out.println("getName方法正在執行");//延遲5秒
Thread.sleep(5000);
}catch(Exception e)
{
}return "火星";
}
}
為了模擬需要一定時間才返回的WebService方法,在getName方法中使用了sleep方法來延遲5秒。
下面是MyService類的配置代碼:
異步調用演示
service.MyService
從上面的配置代碼可以看出,MyService的配置方式與前幾章的WebService的配置方式完全一樣,也就是說,MyService只是一個普通的WebService。
下面是異步調用MyService的Java客戶端代碼:
packageclient;importjavax.xml.namespace.QName;importorg.apache.axis2.addressing.EndpointReference;importorg.apache.axis2.client.Options;importorg.apache.axis2.context.MessageContext;importorg.apache.axis2.rpc.client.RPCServiceClient;public classRPCAsyncClient
{public static void main(String[] args) throwsException
{
RPCServiceClient serviceClient= newRPCServiceClient();
Options options=serviceClient.getOptions();
EndpointReference targetEPR= newEndpointReference("http://localhost:8080/axis2/services/myService");
options.setTo(targetEPR);
Object[] opAddEntryArgs= newObject[]{};
QName opAddEntry= new QName("http://service", "getName");
serviceClient.invokeNonBlocking(opAddEntry, opAddEntryArgs,neworg.apache.axis2.client.async.AxisCallback()
{
@Overridepublic voidonComplete()
{
}
@Overridepublic voidonError(Exception arg0)
{
} }
@Overridepublic voidonFault(MessageContext arg0)
{
}
@Overridepublic voidonMessage(MessageContext mc)
{//輸出返回值
System.out.println(mc.getEnvelope().getFirstElement()
.getFirstElement().getFirstElement().getText());
}
});
System.out.println("異步調用!");//阻止程序退出
System.in.read();
}
}
從上面的代碼可以看出,invokeNonBlocking方法有三個參數,前兩個參數分別指定了要調用的方法及方法參數的相關信息,而最后一個參數并不是方法返回值的類型信息,而是一個實現org.apache.axis2.client.async.AxisCallback接口的類的對象實例。在本例中隱式實現了AxisCallback接口。在AxisCallback接口中有四個方法需要實現,其中當被異步調用的方法返回時onMessage方法被調用。當運行上面的程序后,將輸出如下的信息:
異步調用!
火星
雖然上面的例子可以實現異步調用,但比較麻煩。為了更方便地實現異步調用,可以使用wsdl2java命令的-a參數生成可異步調用的Stub類。下面的命令可生成同步和異步調用的客戶端代碼(兩個類),其中-s表示生成同步調用代碼,-a表示生成異步調用代碼。
%AXIS2_HOME%\bin\wsdl2java?-uri?http://localhost:8080/axis2/services/myService?wsdl?-p?client?-s?-a?-o?stub
在執行上面的命令后,將生成兩個類:MyServiceStub和MyServiceCallbackHandler類,其中MyServiceStub類負責同步和異步調用WebService,MyServiceCallbackHandler類是一個抽象類,也是一個回調類,當使用異步方式調用WebService方法時,如果方法返回,則MyServiceCallbackHandler類的receiveResultgetName方法被調用。下面是使用MyServiceStub類異步訪問WebService的代碼:
packageclient;importclient.MyServiceStub.GetNameResponse;class MyCallback extendsMyServiceCallbackHandler
{
@Overridepublic voidreceiveResultgetName(GetNameResponse result)
{//輸出getName方法的返回結果
System.out.println(result.get_return());
}
}public classStubClient
{public static void main(String[] args) throwsException
{
MyServiceStub stub= newMyServiceStub();//異步調用WebService
stub.startgetName(newMyCallback());
System.out.println("異步調用!");
System.in.read();
}
}
執行上面的程序后,將輸出如下的信息:
異步調用!
火星
在.net中也可以使用異步的方式來調用WebService,如在C#中可使用如下的代碼來異步調用getName方法:
//回調方法
private voidgetNameCompletedEvent(object sender, WSC.asyn.getNameCompletedEventArgs e)
{
listBox1.Items.Add( e.Result.@return);
}private voidbutton1_Click(object sender, EventArgs e)
{
async.myService my= newWSC.async.myService();
my.getNameCompleted+= newWSC.async.getNameCompletedEventHandler(getNameCompletedEvent);
my.getNameAsync();
MessageBox.Show("完成調用");
}
其中async是引用MyService的服務名。要注意的是,在C#中不能在同一個WebService實例的getName方法未返回之前,再次調用該實例的getName方法,否則將拋出異常。如下面的代碼會拋出一個異常:
async.myService my = newWSC.async.myService();
my.getNameCompleted+= newWSC.async.getNameCompletedEventHandler(getNameCompletedEvent);
my.getNameAsync();//將拋出異常
my.getNameAsync();
但不同的WebService實例的方法可以在方法未返回時調用,如下面的代碼是可以正常工作的:
asyn.myService my = newWSC.asyn.myService();
my.getNameAsync();
my.getNameCompleted+= newWSC.asyn.getNameCompletedEventHandler(getNameCompletedEvent);
asyn.myService my1= newWSC.asyn.myService();
my1.getNameCompleted+= newWSC.asyn.getNameCompletedEventHandler(getNameCompletedEvent);
my1.getNameAsync();
Axis2可以通過模塊(Module)進行擴展。Axis2模塊至少需要有兩個類,這兩個類分別實現了Module和Handler接口。開發和使用一個Axis2模塊的步驟如下:
1.?編寫實現Module接口的類。Axis2模塊在進行初始化、銷毀等動作時會調用該類中相應的方法)。
2.?編寫實現Handler接口的類。該類是Axis2模塊的業務處理類。
3.?編寫module.xml文件。該文件放在META-INF目錄中,用于配置Axis2模塊。
4.?在axis2.xml文件中配置Axis2模塊。
5.?在services.xml文件中配置Axis2模塊。每一個Axis2模塊都需要使用元素引用才能使用。
6.?發布Axis2模塊。需要使用jar命令將Axis2模塊壓縮成.mar包(文件擴展名必須是.mar),然后將.mar文件放在
\webapps\axis2\WEB-INF\modules目錄中。
先來編寫一個WebService類,代碼如下:
packageservice;public classMyService
{publicString getGreeting(String name)
{return "您好 " +name;
}
}
下面我們來編寫一個記錄請求和響應SOAP消息的Axis2模塊。當客戶端調用WebService方法時,該Axis2模塊會將請求和響應SOAP消息輸出到Tomcat控制臺上。
第1步:編寫LoggingModule類
LoggingModule類實現了Module接口,代碼如下:
packagemodule;importorg.apache.axis2.AxisFault;importorg.apache.axis2.context.ConfigurationContext;importorg.apache.axis2.description.AxisDescription;importorg.apache.axis2.description.AxisModule;importorg.apache.axis2.modules.Module;importorg.apache.neethi.Assertion;importorg.apache.neethi.Policy;public class LoggingModule implementsModule
{//initialize the module
public voidinit(ConfigurationContext configContext, AxisModule module)throwsAxisFault
{
System.out.println("init");
}public void engageNotify(AxisDescription axisDescription) throwsAxisFault
{
}//shutdown the module
public voidshutdown(ConfigurationContext configurationContext)throwsAxisFault
{
System.out.println("shutdown");
}publicString[] getPolicyNamespaces()
{return null;
}public voidapplyPolicy(Policy policy, AxisDescription axisDescription)throwsAxisFault
{
}public booleancanSupportAssertion(Assertion assertion)
{return true;
}
}
在本例中LoggingModule類并沒實現實際的功能,但該類必須存在。當Tomcat啟動時會裝載該Axis2模塊,同時會調用LoggingModule類的init方法,并在Tomcat控制臺中輸出“init”。
第2步:編寫LogHandler類
LogHandler類實現了Handler接口,代碼如下:
packagemodule;importorg.apache.axis2.AxisFault;importorg.apache.axis2.context.MessageContext;importorg.apache.axis2.engine.Handler;importorg.apache.axis2.handlers.AbstractHandler;importorg.apache.commons.logging.Log;importorg.apache.commons.logging.LogFactory;public class LogHandler extends AbstractHandler implementsHandler
{private static final Log log = LogFactory.getLog(LogHandler.class);privateString name;publicString getName()
{returnname;
}publicInvocationResponse invoke(MessageContext msgContext)throwsAxisFault
{//向Tomcat控制臺輸出請求和響應SOAP消息
log.info(msgContext.getEnvelope().toString());returnInvocationResponse.CONTINUE;
}public voidrevoke(MessageContext msgContext)
{
log.info(msgContext.getEnvelope().toString());
}public voidsetName(String name)
{this.name =name;
}
}
LogHandler類的核心方法是invoke,當使用該Axis2模塊的WebService的方法被調用時,LogHandler類的invoke方法被調用。
第3步:編寫module.xml文件
在META-INF目錄中建立一個module.xml文件,內容如下:
第4步:在axis2.xml文件中配置Axis2模塊
打開axis2.xml文件,分別在如下四個元素中加入:
第5步:在services.xml文件中引用logging模塊
services.xml文件的內容如下:
使用logging模塊
service.MyService
第6步:發布logging模塊
到現在為止,我們應用可以建立兩個發行包:logging.mar和service.aar。其中logging.mar文件是Axis2模塊的發行包,該包的目錄結構如下:
logging.mar
module\LoggingModule.class
module\LogHandler.class
META-INF\module.xml
service.aar文件是本例編寫的WebService發行包,該包的目錄結構如下:
service.aar
service\MyService.class
META-INF\services.xml
將logging.mar文件放在\webapps\axis2\WEB-INF\modules目錄中,將service.aar文件放在\webapps\axis2\WEB-INF\services目錄中。要注意的是,如果modules目錄中包含了modules.list文件,Axis2會只裝載在該文件中引用的Axis2模塊,因此,必須在該文件中引用logging模塊,該文件的內容如下:
addressing-1.4.1.mar
soapmonitor-1.4.1.mar
ping-1.4.1.mar
mex-1.4.1.mar
axis2-scripting-1.4.1.mar
logging.mar
如果modules目錄中不包含modules.list文件,則Axis2會裝載modules文件中的所有Axis2模塊。
現在啟動Tomcat,使用如下的C#代碼調用MyService的getGreeting方法則會在Tomcat控制臺中輸出相應的請求和響應SOAP消息。
//async是引用MyService的服務名
async.myService my = newWSC.asyn.myService();
MessageBox.Show(my.getGreeting("中國"));
MessageBox.Show("完成調用");
在執行上面的代碼后,在Tomcat控制臺中輸出的信息如下圖所示。
在Axis2中提供了一個Axis2模塊(soapmonitor),該模塊實現了與《WebService大講堂之Axis2(9):編寫Axis2模塊(Module)》中實現的logging模塊相同的功能,所不同的是,logging模塊直接將SOAP請求與響應消息輸出到Tomcat控制臺中,而soapmonitor模塊利用applet直接在頁面中輸出SOAP請求和響應消息。
下面是配置和使用soapmonitor模塊的步驟:
第1步:部署Applet和Servlet
由于axis2默認情況下已經自帶了soapmonitor模塊,因此,soapmonitor模塊并不需要單獨安裝。但applet所涉及到的相應的.class文件需要安裝一下。在\webapps\axis2\WEB-INF\lib目錄中找到soapmonitor-1.4.1.jar文件,將該文件解壓。雖然applet并不需要soapmonitor-1.4.1.jar文件中所有的.class文件,但為了方便,讀者也可以直接將解壓目錄中的org目錄復制到\webapps\axis2目錄中,Applet所需的.class文件需要放在這個目錄。然后再將org目錄復制到\webapps\axis2\WEB-INF\classes目錄中,soapmonitor模塊中的Servlet所對應的.class文件需要放在這個目錄。
第2步:配置Servlet
打開\webapps\axis2\WEB-INF\web.xml文件,在其中加入如下的內容:
SOAPMonitorService
org.apache.axis2.soapmonitor.servlet.SOAPMonitorService
SOAPMonitorPort
5001
1
SOAPMonitorService
/SOAPMonitor
第3步:在services.xml文件中引用soapmonitor模塊
與引用logging模塊一樣,引用soapmonitor模塊也需要使用元素,引用soapmonitor模塊的services.xml文件的內容如下:
使用logging和soapmonitor模塊
service.MyService
由于soapmonitor模塊已經在axis2.xml進行配置了,因此,在本例中不需要再對axis2.xml文件進行配置了。
第4步:使用soapmonitor模塊
在瀏覽器中將出現soapmonitor所帶的Applet的界面,當訪問MyService的getGreeting方法時,在Tomcat控制臺與Applet中都顯示了相應的SOAP請求和響應消息。如圖1和圖2分別是調用了兩次getGreeting方法后輸出的SOAP請求和響應消息。
圖1
圖2
如果讀者想讓logging和soapmonitor模塊監視部署在Axis2中的所有WebService,可以在axis2.xml文件中使用元素來引用這兩個模塊,代碼如下:
總結
以上是生活随笔為你收集整理的java axis2 教程_webservice的Axis2入门教程java版的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 台式机计算机怎么分割,编辑手把手教程 如
- 下一篇: 【Python】Python错误、异常和