在實際的應用中,不僅需要使用WebService來傳遞簡單類型的數據,有時也需要傳遞更復雜的數據,這些數據可以被稱為復合類型的數據。數組與類(接口)是比較常用的復合類型。在Axis2中可以直接使用將WebService方法的參數或返回值類型聲明成數組或類(接口)。但要注意,在定義數組類型時只能使用一維數組,如果想傳遞多維數組,可以使用分隔符進行分隔,如下面的代碼所示:

String[] strArray = new String[]{ "自行車,飛機,火箭","中國,美國,德國", "超人,蜘蛛俠,鋼鐵俠" } ;

??? 上面的代碼可以看作是一個3*3的二維數組。

??? 在傳遞類的對象實例時,除了直接將數組類型聲明成相應的類或接口,也可以將對象實例進行序列化,也就是說,將一個對象實例轉換成字節數組進行傳遞,然后接收方再進行反序列化,還原這個對象實例。

??? 下面的示例代碼演示了如何傳遞數組與類(接口)類型的數據,并演示如何使用字節數組上傳圖像。本示例的客戶端代碼使用JavaC#編寫。要完成這個例子需要如下幾步:

一、實現服務端代碼

??? ComplexTypeService是一個WebService類,該類的代碼如下:

import?java.io.FileOutputStream;
import?data.DataForm;

public?class?ComplexTypeService
{
????
//??上傳圖像,imageByte參數表示上傳圖像文件的字節,
????
//??length參數表示圖像文件的字節長度(該參數值可能小于imageByte的數組長度)
????public?boolean?uploadImageWithByte(byte[]?imageByte,?int?length)
????{
????????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;
????}
????
//??返回一維字符串數組
????public?String[]?getArray()
????{
????????String[]?strArray?
=?new?String[]{?"自行車",?"飛機",?"火箭"?};
????????
return?strArray;
????}?
????
//??返回二維字符串數組
????public?String[]?getMDArray()
????{
????????String[]?strArray?
=?new?String[]{?"自行車,飛機,火箭","中國,美國,德國",?"超人,蜘蛛俠,鋼鐵俠"?}?;
????????
return?strArray;
????}
????
//??返回DataForm類的對象實例
????public?DataForm?getDataForm()
????{
????????
return?new?DataForm();
????}
????
//??將DataForm類的對象實例序列化,并返回序列化后的字節數組
????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();
????}????
}

?

二、實現DataForm

??? DataForm是要返回的對象實例所對應的類,該類的實現代碼如下:

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;
????}
}

三、發布WebService

??? 由于本示例的WebService類使用了一個Java類(DataForm類),因此,在發布WebService之前,需要先將DataForm.class文件復制到<Tomcat安裝目錄>\webapps\axis2\WEB-INF\classes\data目錄中,然后將ComplexTypeService.class文件復制到<Tomcat安裝目錄>\webapps\axis2\WEB-INF\pojo目錄中,最后啟動Tomcat(如果Tomcat已經啟動,由于增加了一個DataForm類,因此,需要重新啟動Tomcat)。

四、使用Java編寫調用WebService的客戶端代碼

??? 在客戶端仍然使用了RPC的調用方式,代碼如下:

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);
????????
//?下面的代碼調用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?
=?new?Object[]{?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, 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();
????????
/////////////////////////////////////////?

????????
//?下面的代碼調用了getDataForm方法,并返回DataForm對象實例
????????/////////////////////////////////////////??
????????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());
????????
/////////////////////////////////////////
????????
????????
//?下面的代碼調用了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?
=?new?java.io.ObjectInputStream(
????????????????
new?java.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?=?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);

??? 在獲得二維數組時,可以將數據加載到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方法的調用都非常簡單,讀者可以自己做這個實驗。

??? 要注意的是,由于.netjava序列化和反序列化的差異,通過序列化的方式傳遞對象實例只使用于客戶端與服務端為同一種語言或技術的情況,如客戶端和服務端都使用Java來編寫。

??? 如果讀者要上傳大文件,應盡量使用FTP的方式來傳遞,而只通過WebService方法來傳遞文件名等信息。這樣有助于提高傳輸效率。