復雜對象類型的WebService高級部分


從客戶端除了傳遞字符串以外還可以傳遞復雜對象(對象必須序列化了),List,Map,數組和文件。


(1)定義一個對象實現了serializable 接口
package cn.com.chenlly.ssh.webservice.axis;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

 

 public class Address implements Serializable { //復雜類型的類要序列化
 
 private Integer identifier;
 
 private String address;
 
 private String city;
 
 private String province;
 
 private String country;
 
 private String []array;   //javabean里的復雜類型
 
 private List<Integer> list;(基本類型)
 
 private boolean isExst;
 
 
 //constructor
 public Address(){
 
  list = new ArrayList<Integer>();
 
  list.add(1);
 
  list.add(2);
 
  list.add(3);
 }
 public Integer getIdentifier() {
  return identifier;
 }

 public void setIdentifier(Integer identifier) {
  this.identifier = identifier;
 }

 public String getAddress() {
  return address;
 }

 public void setAddress(String address) {
  this.address = address;
 }

 public String getCity() {
  return city;
 }

 public void setCity(String city) {
  this.city = city;
 }

 public String getProvince() {
  return province;
 }

 public void setProvince(String province) {
  this.province = province;
 }

 public String getCountry() {
  return country;
 }

 public void setCountry(String country) {
  this.country = country;
 }

 public String[] getArray() {
  return array;
 }

 public void setArray(String[] array) {
  this.array = array;
 }

 public List<Integer> getList() {
  return list;
 }

 public void setList(List<Integer> list) {
  this.list = list;
 }

 public boolean isExst() {
  return isExst;
 }

 public void setExst(boolean isExst) {
  this.isExst = isExst;
 }
}

(2)定義server-config.wsdd文件

<deployment xmlns="http://xml.apache.org/axis/wsdd/"
 xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
 <handler name="URLMapper"     //定義了兩個handler(非必須),類似於過濾器
  type="java:org.apache.axis.handlers.http.URLMapper" />
 <handler name="wsTestHandler"
  type="java:cn.com.chenlly.ssh.webservice.axis.WSTestServiceHandle">
  <parameter name="status" value="success" />
 </handler>
 <!-- 自定義服務 -->
 <service name="ws" provider="java:RPC">
  <parameter name="className"
   value="cn.com.chenlly.ssh.webservice.axis.WSTestServiceImpl" />
  <parameter name="allowedMethods" value="*" />
  <parameter name="scope" value="request" />
 
  <responseFlow>
   <handler type="wsTestHandler" />    //響應時使用上面的handler

  </responseFlow>
  <requestFlow>//請求時使用上面的handler
   <handler type="wsTestHandler" />    

  </requestFlow>
 
  <beanMapping qname="myNSD:Address"   //復雜類型javabean(用於傳送的序列化對象)
   xmlns:myNSD="urn:AddressManager"
   languageSpecificType="java:cn.com.chenlly.ssh.webservice.axis.Address">
  </beanMapping>
 </service>

 <transport name="http">
  <requestFlow>
   <handler type="URLMapper" />
  </requestFlow>
 </transport>
</deployment>

//主要是<beanMapping>標簽中名字空間和qname寫法
第一個你自定義的命名空間和第二個節點本地部分會組成一個新的QName。


生成的WSDL有如下一段
- <schema targetNamespace="urn:AddressManager" xmlns="http://www.w3.org/2001/XMLSchema">
  <import namespace="http://192.168.1.98:8082/SSHProject/services/ws" />
  <import namespace="http://xml.apache.org/xml-soap" />
  <import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
- <complexType name="Address">
- <sequence>
  <element name="address" nillable="true" type="soapenc:string" />
  <element name="array" nillable="true" type="impl:ArrayOf_soapenc_string" />
  <element name="city" nillable="true" type="soapenc:string" />
  <element name="country" nillable="true" type="soapenc:string" />
  <element name="exst" type="xsd:boolean" />
  <element name="identifier" nillable="true" type="soapenc:int" />
  <element name="list" nillable="true" type="impl:ArrayOf_xsd_anyType" />
  <element name="province" nillable="true" type="soapenc:string" />
  </sequence>
  </complexType>
  </schema>
這個新的schema就是把對象序列化以后生成了xml流文件。

(3) webService 服務方法
public Address dealAddress(Address address) {
   System.out.println("service exst:"+address.isExst());
   //客戶端對象傳遞過來設置標志為true
   address.setExst(true);
   return address;
}

(4) 客戶端
package cn.com.chenlly.ssh.webservice.axis;

import java.util.ArrayList;
import java.util.List;

import javax.xml.namespace.QName;
import javax.xml.rpc.ParameterMode;

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.ser.BeanDeserializerFactory;
import org.apache.axis.encoding.ser.BeanSerializerFactory;

 

 

 public class WSTestServiceClient {
 public static void main(String[] args) {
  Service service = new Service();
  try {
   Call call = (Call) service.createCall();
   String url = "http://192.168.1.98:8082/SSHProject/services/ws?wsdl";
   call.setTargetEndpointAddress(new java.net.URL(url));
                        //定義對象
   Address address = new Address();
   address.setIdentifier(1);
   address.setProvince("湖南");
   address.setCity("長沙");
   address.setExst(false);

   QName qn = new QName("urn:AddressManager", "Address");//第一個參數名字空間URI,第二個參數本地部分,注意這兩部分在server-config.wsdd文件中標簽beanMapping配置
   call.registerTypeMapping(Address.class, qn,
     new BeanSerializerFactory(Address.class, qn),//序列化
     new BeanDeserializerFactory(Address.class, qn));
 
   call.setOperationName(new QName(url,"dealAddress"));
 
   call.addParameter("arg0", qn, ParameterMode.IN);//定義一個參數類型,如果是String類型的參數可以不需要這句話
   call.setReturnClass(Address.class);//指定返回類型
 
   Address result = (Address) call.invoke(new Object[]{address});//這里傳遞給service的是一個對象
   System.out.println(result.isExst());
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}
//在服務器端打印的isExst()方法是false;然后設置address的exst為true;最后又傳送到客戶端打印的result結果為true

 

<beanMapping/> 需要說明的是:

1 如果服務中不需要傳遞對象,是不需要<beanMapping/>對的.而且這里面的對象必須要是符合javaBean模式的對象,最起碼要符合get/set方法對.

2 qname xmlns:xx languageSpecificType分別用於指定參數對象的命名空間.用於在客戶端調用.

 

 

 

二、開發service
服務器端的service為普通的java類:com.hnisi.axis.BookOrder

public class BookOrder {
public String getName(String name) {
System.out.println("start execute ...");
return "book name: " + name;
}

public Book setPrice(Book book){
book.setPrice(10);
return book;
}
}

com.hnisi.axis.Book為簡單的值對象,包含兩個屬性name,price。

三、發布service(將會錯誤)
1、手工修改server-config.wsdd文件(在已有server-config.wsdd文件的情況下)
添加service:

<service name="BookOrder" provider="java:RPC">
<parameter name="allowedMethods" value="*"/>
<parameter name="className" value="com.hnisi.axis.BookOrder"/>
</service>

 

 

原因:

由於SOAP中值的類型就是XML Schema中的基本類型,默認只支持簡單類型和數組。所以在進行對象傳遞的過程中,需要進行序列化和反序列化。

Axis為提供了大量的序列化/反序列化器,能夠基本滿足大部分應用:
1、基本類型,如int、double等,轉換成基本對象類型java.lang.Integer、java.lang.Double。
2、常用集合對象的轉換
java.util.List ==> java.lang.Object[]
java.util.Vector  ==> java.util.Vector
3、普通JavaBean(簡單值對象)的序列化和反序列化
首先,在web service部署端,修改server-config.wsdd文件,在具體的service配置,增加如下代碼:
<beanMapping languageSpecificType="java:com.hnisi.axis.Book" qname="ns1:Book"
         xmlns:ns1="urn:BeanService"/>
languageSpecificType屬性指定JavaBean類文件位置,qname屬性指定JavaBean類的名字。當然,一個service可以綁定多個bean對象。

其次,在客戶端,完成對象的注冊。
對於調用方法一中,需要新增如下代碼以完成注冊:
QName qn = new QName("urn:BeanService","Book");
call.registerTypeMapping(Book.class, qn,
new BeanSerializerFactory(Book.class, qn),
                    new BeanDeserializerFactory(Book.class, qn));
而對於調用方法二,重新根據wsdl生成java代碼,已完成必要的對象注冊過程,CallService中可以直接傳遞Book對象了。

 

 

 

1)axis1.2內在支持的幾種對象類型。
          這幾種內在支持的對象包括:
          java基本類型 : int, float,,,,
          基本類型包裝類 : Integer, Float, Long...
          還有String, Date, Calendar, BigDecimal, BigInteger, List, Map.
     凡是這些內在支持的對象, 不管他們作為某個Service的input 還是 output, 我們在服務端的axis1.2的WEB-INF/server-config.wsdd的該Service的定義中都不需要加入 <beanMapping>或者是<typeMapping>的聲明。

2)簡單的javabean對象類型。所有的field都是上面提到的基本類型

由於MyBean是一個自定義的JavaBean對象, 所以在server-config.wsdd中就必須加上<beanMapping ...../>的聲明, 讓axis知道怎么把request中xml數據deserialize為MyBean對象,又如何把MyBean對象serialize為xml數據作為response.用wtp自動為JavaInputService生成的wsdl中, MyBean是作為一個complexType在wsdl中定義的。

3)復雜一點的JavaBean對象。
        比如JavaBean對象中的一些field又是自定義的JavaBean,  這種情況下, wsdl中生成的complextype會有多個(webservice接口最好不用定義多層的結構),而在wsdd定義的<beanMapping .../>也會有多個, axis1.2支持起來都是易如反掌。

4)java中的數組

在webservice中把List, Map作為service的input, output的做法都是不可行的。至少在jdk1.4的版本中是這樣的。

 要注意的是,數組參數在server-config.wsdd中需要配置<arrayMapping.../>

 似乎List, Map的問題用數組就可以解決了。事實上就是如此。但是還得注意的是:
   javabean里邊也不能含有List?. 如果MyBean跟其它某個對象是1:n的關系,那么也只能寫成數組的形式,而不能是List的形式

 

      例子:

      <service name="StudentInfoService" provider="java:RPC">  

              <parameter name="className" value="com.kevinGQ.service.axis.service.GetStudentService"/>  

              <parameter name="allowedMethods" value="*"/>  

             <beanMapping qname="myNS:Student" xmlns:myNS="urn:StudentInfoService" languageSpecificType="java:com.kevinGQ.service.axis.model.Student"/>  

       </service> 

片斷中StudentInfoService是這個web service的名字,在客戶端編碼的時候需要用到。

<parameter name="className" value="com.kevinGQ.service.axis.service.GetStudentService"/>

中說明了這個服務提供的類,包括package的完整類名。

<parameter name="allowedMethods" value="*"/>中說明這個服務中可供給外部調用的方法有哪些,*表示全部函數,現在也可以把*改成getAStudent.

<beanMapping qname="myNS:Student" xmlns:myNS="urn:StudentInfoService" languageSpecificType="java:com.kevinGQ.service.axis.model.Student"/>中說明對於這個JavaBean的傳輸需要如何對它進行serializing和de-serializing,說明的目的在於綁定JavaBean的對象類別。注意標簽中說明的名字空間。這個標簽其實是如下標簽的一個簡寫:

Java代碼 

1         <typeMapping qname="myNs:Student" xmlns:ns="urn:StudentInfoService" 

2                      languageSpecificType="java: com.kevinGQ.service.axis.model.Student " 

3                      serializer="org.apache.axis.encoding.ser.BeanSerializerFactory " 

4                      deserializer=" org.apache.axis.encoding.ser.BeanDeserializerFactory " 

5                      encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>

 

 

 

 

 

特別說明:

A、 如果你調用的方法有返回值,一定要設置返回值的類型。call.setReturnClass

B、 如果你調用的方法有參數,一定要設置參數的類型call.addParameter

C、 記得添加wsdl4j.jar,序列化轉換的時候需要用到,否則會出現找不到類型異常

如:

 call.addParameter("i", XMLType.XSD_INT, ParameterMode.IN);
 call.setReturnClass(User[].class);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM