zoukankan      html  css  js  c++  java
  • 复杂对象类型的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);

  • 相关阅读:
    原型链与继承
    js错误处理Try-catch和throw
    函数柯里化
    js函数节流
    事件委托
    innerHTML属性的内存和性能问题
    微信小程序左滑显示按钮demo
    this的作用
    前端工作面试经典问题(超级全)
    HTML5入门指南
  • 原文地址:https://www.cnblogs.com/qqzy168/p/3140022.html
Copyright © 2011-2022 走看看