在實際的應用中,不僅需要使用WebService來傳遞簡單類型的數據,有時也需要傳遞更復雜的數據, 這些數據可以被稱為復合類型的數據。數組與類(接口)是比較常用的復合類型。在Axis2中可以直接使 用將WebService方法的參數或返回值類型聲明成數組或類(接口)。但要注意,在定義數組類型時只能使 用一維數組,如果想傳遞多維數組,可以使用分隔符進行分隔,如下面的代碼所示:
String[] strArray = new String[]{ "自行車,飛機,火箭","中國,美國,德國", "超人,蜘蛛俠,鋼鐵 俠" } ;
上面的代碼可以看作是一個3*3的二維數組。
在傳遞類的對象實例時,除了直接將數組類型聲明成相應的類或接口,也可以將對象實例進行序列化 ,也就是說,將一個對象實例轉換成字節數組進行傳遞,然後接收方再進行反序列化,還原這個對象實例 。
下面的示例代碼演示了如何傳遞數組與類(接口)類型的數據,並演示如何使用字節數組上傳圖像。 本示例的客戶端代碼使用Java和C#編寫。要完成這個例子需要如下幾步:
一、實現服務端代碼
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方法的調用都非常簡單,讀者可以自己做這個實驗。
要注意的是,由於.net和java序列化和反序列化的差異,通過序列化的方式傳遞對象實例只使用於客 戶端與服務端為同一種語言或技術的情況,如客戶端和服務端都使用Java來編寫。
如果讀者要上傳大文件,應盡量使用FTP的方式來傳遞,而只通過WebService方法來傳遞文件名等信息 。這樣有助於提高傳輸效率。