在實(shí)際的應(yīng)用中,不僅需要使用WebService
來(lái)傳遞簡(jiǎn)單類(lèi)型的數(shù)據(jù),有時(shí)也需要傳遞更復(fù)雜的數(shù)據(jù),這些數(shù)據(jù)可以被稱(chēng)為復(fù)合類(lèi)型的數(shù)據(jù)。數(shù)組與類(lèi)(接口)是比較常用的復(fù)合類(lèi)型。在Axis2
中可以直接使用將WebService
方法的參數(shù)或返回值類(lèi)型聲明成數(shù)組或類(lèi)(接口)。但要注意,在定義數(shù)組類(lèi)型時(shí)只能使用一維數(shù)組,如果想傳遞多維數(shù)組,可以使用分隔符進(jìn)行分隔,如下面的代碼所示:String[] strArray = new String[]{ "自行車(chē),飛機(jī),火箭","中國(guó),美國(guó),德國(guó)", "超人,蜘蛛俠,鋼鐵俠" } ;
??? 上面的代碼可以看作是一個(gè)3*3的二維數(shù)組。
??? 在傳遞類(lèi)的對(duì)象實(shí)例時(shí),除了直接將數(shù)組類(lèi)型聲明成相應(yīng)的類(lèi)或接口,也可以將對(duì)象實(shí)例進(jìn)行序列化,也就是說(shuō),將一個(gè)對(duì)象實(shí)例轉(zhuǎn)換成字節(jié)數(shù)組進(jìn)行傳遞,然后接收方再進(jìn)行反序列化,還原這個(gè)對(duì)象實(shí)例。
??? 下面的示例代碼演示了如何傳遞數(shù)組與類(lèi)(接口)類(lèi)型的數(shù)據(jù),并演示如何使用字節(jié)數(shù)組上傳圖像。本示例的客戶(hù)端代碼使用Java和C#編寫(xiě)。要完成這個(gè)例子需要如下幾步:
一、實(shí)現(xiàn)服務(wù)端代碼
??? ComplexTypeService是一個(gè)WebService類(lèi),該類(lèi)的代碼如下:
import?java.io.FileOutputStream;
import?data.DataForm;
public?class?ComplexTypeService
{
????//??上傳圖像,imageByte參數(shù)表示上傳圖像文件的字節(jié),
????//??length參數(shù)表示圖像文件的字節(jié)長(zhǎng)度(該參數(shù)值可能小于imageByte的數(shù)組長(zhǎng)度)
????public?boolean?uploadImageWithByte(byte[]?imageByte,?int?length)
????{
????????FileOutputStream?fos?=?null;
????????try
????????{
????????????//??將上傳的圖像保存在D盤(pán)的test1.jpg文件中
????????????fos?=?new?FileOutputStream("d:\\test1.jpg");
????????????//??開(kāi)始寫(xiě)入圖像文件的字節(jié)
????????????fos.write(imageByte,?0,?length);
????????????fos.close();
????????}
????????catch?(Exception?e)
????????{
????????????return?false;
????????}
????????finally
????????{
????????????if?(fos?!=?null)
????????????{
????????????????try
????????????????{
????????????????????fos.close();
????????????????}
????????????????catch?(Exception?e)
????????????????{
????????????????}
????????????}
????????}
????????return?true;
????}
????//??返回一維字符串?dāng)?shù)組
????public?String[]?getArray()
????{
????????String[]?strArray?=?new?String[]{?"自行車(chē)",?"飛機(jī)",?"火箭"?};
????????return?strArray;
????}?
????//??返回二維字符串?dāng)?shù)組
????public?String[]?getMDArray()
????{
????????String[]?strArray?=?new?String[]{?"自行車(chē),飛機(jī),火箭","中國(guó),美國(guó),德國(guó)",?"超人,蜘蛛俠,鋼鐵俠"?}?;
????????return?strArray;
????}
????//??返回DataForm類(lèi)的對(duì)象實(shí)例
????public?DataForm?getDataForm()
????{
????????return?new?DataForm();
????}
????//??將DataForm類(lèi)的對(duì)象實(shí)例序列化,并返回序列化后的字節(jié)數(shù)組
????public?byte[]?getDataFormBytes()?throws?Exception?
????{
????????java.io.ByteArrayOutputStream?baos?=?new?java.io.ByteArrayOutputStream();
????????java.io.ObjectOutputStream?oos?=?new?java.io.ObjectOutputStream(baos);
????????oos.writeObject(new?DataForm());????????
????????return?baos.toByteArray();
????}????
}
?
二、實(shí)現(xiàn)DataForm類(lèi)
??? DataForm是要返回的對(duì)象實(shí)例所對(duì)應(yīng)的類(lèi),該類(lèi)的實(shí)現(xiàn)代碼如下:
package?data;
public?class?DataForm?implements?java.io.Serializable
{
????private?String?name?=?"bill";
????private?int?age?=?20;
????public?String?getName()
????{
????????return?name;
????}
????public?void?setName(String?name)
????{
????????this.name?=?name;
????}
????public?int?getAge()
????{
????????return?age;
????}
????public?void?setAge(int?age)
????{
????????this.age?=?age;
????}
}
三、發(fā)布WebService
??? 由于本示例的WebService類(lèi)使用了一個(gè)Java類(lèi)(DataForm類(lèi)),因此,在發(fā)布WebService之前,需要先將DataForm.class文件復(fù)制到<Tomcat安裝目錄>\webapps\axis2\WEB-INF\classes\data目錄中,然后將ComplexTypeService.class文件復(fù)制到<Tomcat安裝目錄>\webapps\axis2\WEB-INF\pojo目錄中,最后啟動(dòng)Tomcat(如果Tomcat已經(jīng)啟動(dòng),由于增加了一個(gè)DataForm類(lèi),因此,需要重新啟動(dòng)Tomcat)。
四、使用Java編寫(xiě)調(diào)用WebService的客戶(hù)端代碼
??? 在客戶(hù)端仍然使用了RPC的調(diào)用方式,代碼如下:
package?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;
public?class?ComplexTypeRPCClient
{
????public?static?void?main(String[]?args)?throws?Exception
????{
????????RPCServiceClient?serviceClient?=?new?RPCServiceClient();
????????Options?options?=?serviceClient.getOptions();
????????EndpointReference?targetEPR?=?new?EndpointReference(
????????????????"http://localhost:8080/axis2/services/ComplexTypeService");
????????options.setTo(targetEPR);
????????//?下面的代碼調(diào)用uploadImageWithByte方法上傳圖像文件
????????/////////////////////////////////////////
????????//?打開(kāi)圖像文件,確定圖像文件的大小
????????java.io.File?file?=?new?java.io.File("f:\\images.jpg");
????????java.io.FileInputStream?fis?=?new?java.io.FileInputStream("f:\\images.jpg");
????????//?創(chuàng)建保存要上傳的圖像文件內(nèi)容的字節(jié)數(shù)組
????????byte[]?buffer?=?new?byte[(int)?file.length()];
????????//?將圖像文件的內(nèi)容讀取buffer數(shù)組中
????????int?n?=?fis.read(buffer);
????????System.out.println("文件長(zhǎng)度:"?+?file.length());
????????Object[]?opAddEntryArgs?=?new?Object[]{?buffer,?n?};
????????Class[]?classes?=?new?Class[]{?Boolean.class?};
????????QName?opAddEntry?=?new?QName("http://ws.apache.org/axis2","uploadImageWithByte");
????????fis.close();
????????//?開(kāi)始上傳圖像文件,并輸出uploadImageWithByte方法的返回傳
????????System.out.println(serviceClient.invokeBlocking(opAddEntry,opAddEntryArgs,?classes)[0]);
????????/////////////////////////////////////////
????????
????????//?下面的代碼調(diào)用了getArray方法,并返回一維String數(shù)組
????????/////////////////////////////////////////??
????????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();
????????/////////////////////////////////////////?
????????
????????//?下面的代碼調(diào)用了getMDArray方法,并返回一維String數(shù)組
????????/////////////////////////////////////////??
????????opAddEntry?=?new?QName("http://ws.apache.org/axis2",?"getMDArray");
????????strArray?=?(String[])?serviceClient.invokeBlocking(opAddEntry, new?Object[]{},
????????????????????????????????????????????????????????? new?Class[]{String[].class})[0];
????????for?(String?s?:?strArray)
????????{
????????????String[]?array?=?s.split(",");
????????????for(String?ss:?array)
????????????????System.out.print("<"?+?ss?+?">?");
????????????System.out.println();
????????}
????????System.out.println();
????????/////////////////////////////////////////?
????????//?下面的代碼調(diào)用了getDataForm方法,并返回DataForm對(duì)象實(shí)例
????????/////////////////////////////////////////??
????????opAddEntry?=?new?QName("http://ws.apache.org/axis2",?"getDataForm");
????????data.DataForm?df?=?(data.DataForm)?serviceClient.invokeBlocking(opAddEntry,?new?Object[]{},
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new?Class[]{data.DataForm.class})[0];
????????System.out.println(df.getAge());
????????/////////////////////////////////////////
????????
????????//?下面的代碼調(diào)用了getDataFormBytes方法,并返回字節(jié)數(shù)組,最后將返回的字節(jié)數(shù)組反序列化后,轉(zhuǎn)換成DataForm對(duì)象實(shí)例
????????/////////////////////////////////////////??????????
????????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?=?new?java.io.ObjectInputStream(
????????????????new?java.io.ByteArrayInputStream(buffer));
????????df?=?(data.DataForm)?ois.readObject();
????????System.out.println(df.getName());
????????//////////////////////////////////////////
????}
}
??? 運(yùn)行上面的程序,將輸出如下的內(nèi)容:
文件長(zhǎng)度:3617
true
自行車(chē)?飛機(jī)?火箭?
<自行車(chē)>?<飛機(jī)>?<火箭>
<中國(guó)>?<美國(guó)>?<德國(guó)>
<超人>?<蜘蛛俠>?<鋼鐵俠>
20
bill
五、使用C#編寫(xiě)調(diào)用WebService的客戶(hù)端代碼
??? 在Visual Studio中使用WebService就簡(jiǎn)單得多。假設(shè)引用WebService時(shí)的引用名為complexType,則下面的代碼調(diào)用了uploadImageWithByte方法來(lái)上傳圖像文件。在Visual Studio引用WebService時(shí),uploadImageWithByte方法多了兩個(gè)out參數(shù),在使用時(shí)要注意。
complexType.ComplexTypeService?cts?=?new?WSC.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);
??? 在獲得二維數(shù)組時(shí),可以將數(shù)據(jù)加載到DataGridView或其他類(lèi)似的控件中,代碼如下:
String[]?strArray?=?cts.getMDArray();
for?(int?i?=?0;?i?<?strArray.Length;?i++)
{
????//??用正則表達(dá)式將帶分隔符的字符串轉(zhuǎn)換成String數(shù)組
????String[]?columns?=?strArray[i].Split(',');
????//??如果DataGridView的表頭不存在,向DataGridView控件添加三個(gè)帶表頭的列
????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控件添加數(shù)據(jù)后的效果如圖1所示。

圖1?
??? 對(duì)于其他的WebService方法的調(diào)用都非常簡(jiǎn)單,讀者可以自己做這個(gè)實(shí)驗(yàn)。
??? 要注意的是,由于.net和java序列化和反序列化的差異,通過(guò)序列化的方式傳遞對(duì)象實(shí)例只使用于客戶(hù)端與服務(wù)端為同一種語(yǔ)言或技術(shù)的情況,如客戶(hù)端和服務(wù)端都使用Java來(lái)編寫(xiě)。
??? 如果讀者要上傳大文件,應(yīng)盡量使用FTP的方式來(lái)傳遞,而只通過(guò)WebService方法來(lái)傳遞文件名等信息。這樣有助于提高傳輸效率。