通过WSDL生成客户端代码

本文介绍如何使用WSDL2Java工具从WSDL文件生成Java客户端和服务端代码,包括类、接口、存根和骨架等组件。同时也介绍了如何利用Java2WSDL工具从Java类生成WSDL文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.WSDL2Java:Building stubs,skeletons,and data types from WSDL. 1

1.1示例...1

1.2测试...4

1.2.1异常:没有定义com.pan.model.User的序列化的实现...5

1.3WSDL与生成的客户端代码结构分析...5

1.3.1Types.6

1.3.2Holders.12

1.3.3PortTypes.13

1.3.4Bindings.13

1.3.5 Services.14

1.3.6 Server-side 绑定...16

2.Java2WSDL.19

2.1步骤...19

2.1.1提供一个Java接口或类...19

2.1.2使用Java2WSDL创建WSDL.19

 

 

 

WSDL(Web Service Description Language),描述一个服务。

Axis支持三种方式操作WSDL:

1 当部署一个服务在Axis中时,可以通过在服务的地址后面加上”?WSDL”,这样会自动生成WSDL文档。例:http://localhost:8080/axis/services/MessageService?wsdl

2 提供”WSDL2Java”工具使用WSDL描述来生成Java代理和skeletons

3 提供”Java2WSDL”工具通过JavaClasses生成WSDL

 

1.WSDL2Java:Building stubs,skeletons,and data types from WSDL

使用org.apache.axis.wsdl.WSDL2Java来生成Java代码

% java -cp %AXISCLASSPATH%org.apache.axis.wsdl.WSDL2Java  (WSDL-file-URL)

1.1示例

Java代码:

/**
 * 用户信息服务接口
 * @author
 *
 */
public interface IUserService {
 
   User queryUser(int id);
  
   void addUser(User user);
  
   List<User> queryList();
  
   String queryUser();
}
 
/**
 * 对外提供查询用户信息服务
 * @author
 *
 */
public class UserService implements IUserService {
 
   @Override
   public User queryUser(int id) {
      return new User(id, "李四 ", 20, "男", "湖南长沙");
   }
 
   @Override
   public void addUser(User user) {
     
   }
 
   @Override
   public List<User> queryList() {
      List<User> userList = newArrayList<User>();
      userList.add(new User(1, "lisi", 23, "男", "南山"));
      userList.add(new User(2, "lisi", 23, "男", "南山"));
      userList.add(new User(3, "lisi", 23, "男", "南山"));
      userList.add(new User(4, "lisi", 23, "男", "南山"));
      userList.add(new User(5, "lisi", 23, "男", "南山"));
      userList.add(new User(6, "lisi", 23, "男", "南山"));
      return userList;
   }
 
   @Override
   public StringqueryUser() {
      return"李四";
   }
  
  
}
 
public class User {
  
   private int id;
   private String name;
   private int age;
   private String sex;
   private String address;
   //get、set方法省略
   public User(int id, String name, int age, String sex, Stringaddress) {
      super();
      this.id = id;
      this.name = name;
      this.age = age;
      this.sex = sex;
      this.address = address;
   }
   public User() {
      super();
   }
  
}


deploy.wsdd:

<!-- Use this fileto deploy some handlers/chains and services     -->
<!-- Two ways to dothis:                                          -->
<!--   java org.apache.axis.client.AdminClientdeploy.wsdd          -->
<!--      after the axis server is running                          -->
<!-- or                                                            -->
<!--   java org.apache.axis.utils.Adminclient|server deploy.wsdd   -->
<!--      from the same directory that the Axis engineruns         -->
 
<deployment name="test"xmlns="http://xml.apache.org/axis/wsdd/"
   xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
 
 
  <service name="userservice"provider="java:RPC">
   
   
    <parameter name="className"value="com.pan.service.impl.UserService"/>
    <parameter name="allowedMethods"value="*"/>
 
   <typeMapping qname="ns:user" xmlns:ns="http://localhost:8080/axis_test/services/userservice/local"
   languageSpecificType="java:com.pan.model.User"
   serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"
   deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"
   encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
  </service>
 
</deployment>

 

发布服务,并保存userservice.wsdl文件

生成客户端代码,代码结构为:

com

       pan

              model

                     User.java

localhost

       axis_test

              services

                     userservice

                            UserService.java

                            UserServiceService.java

                            UserServiceServiceLocator.java

                            UserserviceSoapBindingStub.java

1.2测试

测试代码:


public class ClientTest {
  
   public static void main(String[] args) {
      UserServiceServiceLocator locator = newUserServiceServiceLocator();
      try {
         UserService userService = locator.getuserservice();
         User user = userService.queryUser(1);
         System.out.println(user.getName());
      } catch (ServiceException | RemoteException e) {
         e.printStackTrace();
      }
     
   }
 
}

1.2.1异常:没有定义com.pan.model.User的序列化的实现

   这个问题的原因是默认情况下Axis只对java对的基本类型进行序列化和反序列化的实现,至于自己定义的类的序列化和反序列化可以自己配置,通过<typeMapping>元素配置,可以配置为Axis中已实现的序列化和反序列化类

<typeMapping qname="ns:user" xmlns:ns="http://localhost:8080/axis_test/services/userservice/local"
   languageSpecificType="java:com.pan.model.User"
   serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"
   deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"
   encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>


1.3WSDL与生成的客户端代码结构分析

WSDL clause

Java class(es) generated

For each entry in the type section

A java class


For each portType

A java interface

For each binding

A stub class

For each service

A service interface

A service implementation (the locator)


1.3.1Types

通过WSDL中type来生成Java类,通常这个类是一个Java Bean。例

<complexType name="user">
<sequence>
<element name="address" nillable="true" type="xsd:string"/>
<element name="age" type="xsd:int"/>
<element name="id" type="xsd:int"/>
<element name="name" nillable="true" type="xsd:string"/>
<element name="sex" nillable="true" type="xsd:string"/>
</sequence>
</complexType>


生成的Java代码为:

/**
 *User.java
 *
 *This file was auto-generated from WSDL
 * bythe Apache Axis 1.4 Apr 22, 2006 (06:55:48 PDT) WSDL2Java emitter.
 */
 
package com.pan.model;
 
public class User  implements java.io.Serializable {
   private java.lang.String address;
 
   private int age;
 
   private int id;
 
   private java.lang.String name;
 
   private java.lang.String sex;
 
   public User() {
    }
 
   public User(
          java.lang.String address,
          int age,
          int id,
          java.lang.String name,
          java.lang.String sex) {
          this.address = address;
          this.age = age;
          this.id = id;
          this.name = name;
          this.sex = sex;
    }
 
 
   /**
    * Gets the address value for this User.
    *
    * @return address
    */
   public java.lang.String getAddress() {
       return address;
    }
 
 
   /**
    * Sets the address value for this User.
    *
    * @param address
    */
   public void setAddress(java.lang.String address) {
       this.address = address;
    }
 
 
   /**
    * Gets the age value for this User.
    *
    * @return age
    */
   public int getAge() {
       return age;
    }
 
 
   /**
    * Sets the age value for this User.
    *
    * @param age
    */
   public void setAge(int age) {
       this.age = age;
    }
 
 
   /**
    * Gets the id value for this User.
    *
    * @return id
    */
   public int getId() {
       return id;
    }
 
 
   /**
    * Sets the id value for this User.
    *
    * @param id
    */
   public void setId(int id) {
       this.id = id;
    }
 
 
   /**
     * Gets the name value for this User.
    *
    * @return name
    */
   public java.lang.String getName() {
       return name;
    }
 
 
   /**
    * Sets the name value for this User.
    *
    * @param name
    */
   public void setName(java.lang.String name) {
       this.name = name;
    }
 
 
   /**
    * Gets the sex value for this User.
    *
    * @return sex
    */
   public java.lang.String getSex() {
       return sex;
    }
 
 
   /**
    * Sets the sex value for this User.
     *
    * @param sex
    */
   public void setSex(java.lang.String sex) {
       this.sex = sex;
    }
 
   private java.lang.Object __equalsCalc = null;
   public synchronized boolean equals(java.lang.Object obj) {
       if (!(obj instanceof User)) return false;
       User other = (User) obj;
       if (obj == null) return false;
       if (this == obj) return true;
       if (__equalsCalc != null) {
           return (__equalsCalc == obj);
       }
       __equalsCalc = obj;
       boolean _equals;
       _equals = true &&
           ((this.address==null && other.getAddress()==null) ||
            (this.address!=null &&
             this.address.equals(other.getAddress()))) &&
           this.age == other.getAge() &&
           this.id == other.getId() &&
           ((this.name==null && other.getName()==null) ||
            (this.name!=null &&
             this.name.equals(other.getName()))) &&
           ((this.sex==null && other.getSex()==null) ||
            (this.sex!=null &&
             this.sex.equals(other.getSex())));
       __equalsCalc = null;
       return _equals;
    }
 
   private boolean __hashCodeCalc = false;
   public synchronized int hashCode() {
       if (__hashCodeCalc) {
           return 0;
        }
       __hashCodeCalc = true;
       int _hashCode = 1;
       if (getAddress() != null) {
           _hashCode += getAddress().hashCode();
       }
       _hashCode += getAge();
       _hashCode += getId();
       if (getName() != null) {
            _hashCode += getName().hashCode();
       }
       if (getSex() != null) {
           _hashCode += getSex().hashCode();
       }
       __hashCodeCalc = false;
       return _hashCode;
    }
 
   // Type metadata
   private static org.apache.axis.description.TypeDesc typeDesc =
       new org.apache.axis.description.TypeDesc(User.class, true);
 
   static {
       typeDesc.setXmlType(newjavax.xml.namespace.QName("http://model.pan.com", "User"));
       org.apache.axis.description.ElementDesc elemField = neworg.apache.axis.description.ElementDesc();
       elemField.setFieldName("address");
       elemField.setXmlName(new javax.xml.namespace.QName("","address"));
       elemField.setXmlType(new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema","string"));
       elemField.setNillable(true);
       typeDesc.addFieldDesc(elemField);
       elemField = new org.apache.axis.description.ElementDesc();
       elemField.setFieldName("age");
       elemField.setXmlName(new javax.xml.namespace.QName("","age"));
       elemField.setXmlType(newjavax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema","int"));
       elemField.setNillable(false);
       typeDesc.addFieldDesc(elemField);
       elemField = new org.apache.axis.description.ElementDesc();
       elemField.setFieldName("id");
       elemField.setXmlName(new javax.xml.namespace.QName("","id"));
       elemField.setXmlType(newjavax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema","int"));
       elemField.setNillable(false);
       typeDesc.addFieldDesc(elemField);
       elemField = new org.apache.axis.description.ElementDesc();
       elemField.setFieldName("name");
       elemField.setXmlName(new javax.xml.namespace.QName("","name"));
       elemField.setXmlType(newjavax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema","string"));
       elemField.setNillable(true);
       typeDesc.addFieldDesc(elemField);
       elemField = new org.apache.axis.description.ElementDesc();
       elemField.setFieldName("sex");
       elemField.setXmlName(new javax.xml.namespace.QName("","sex"));
       elemField.setXmlType(newjavax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema","string"));
       elemField.setNillable(true);
        typeDesc.addFieldDesc(elemField);
    }
 
   /**
    * Return type metadata object
    */
   public static org.apache.axis.description.TypeDesc getTypeDesc() {
       return typeDesc;
    }
 
   /**
    * Get Custom Serializer
    */
   public static org.apache.axis.encoding.Serializer getSerializer(
          java.lang.String mechType,
          java.lang.Class _javaType, 
          javax.xml.namespace.QName _xmlType) {
       return
         new org.apache.axis.encoding.ser.BeanSerializer(
           _javaType, _xmlType, typeDesc);
    }
 
   /**
    * Get Custom Deserializer
    */
   public static org.apache.axis.encoding.Deserializer getDeserializer(
          java.lang.String mechType,
          java.lang.Class _javaType,  
          javax.xml.namespace.QName _xmlType) {
       return
         new org.apache.axis.encoding.ser.BeanDeserializer(
           _javaType, _xmlType, typeDesc);
    }
 
}


 

1.3.2Holders

这种类型可作为输入输出参数,Java没有输入/出参数的概念,为了实现这种行为,定义了holder类,这个holder类简单的包括原有类的一个实例。

package samples.addr.holders;
 
public final class PhoneHolder implementsjavax.xml.rpc.holders.Holder {
  publicsamples.addr.Phone value;
 
  publicPhoneHolder() {
  }
 
  publicPhoneHolder(samples.addr.Phone value) {
    this.value =value;
  }
}


A holder class is only generated for a type if that type isused as an inout or out parameter. Note that the holder class has the suffix"Holder" appended to the class name, and it is generated in asub-package with the "holders".

The holder classesfor the primitive types can be found in javax.xml.rpc.holders.

1.3.3PortTypes

Service Definition Interface(SDI)来自WSDL的portType,这个接口允许你去访问服务的方法。WSDL示例:

<message name="empty">
<message name="AddEntryRequest">
  <partname="name" type="xsd:string"/>
  <partname="address" type="typens:address"/>
</message>
<portType name="AddressBook">
  <operationname="addEntry">
    <inputmessage="tns:AddEntryRequest"/>
    <outputmessage="tns:empty"/>
 </operation>
</portType>


生成的SDI:

public interface AddressBook extends java.rmi.Remote {
  public voidaddEntry(String name, Address address) throws
     java.rmi.RemoteException;
}

 

SDI的名字通常是通过portType的name来确定,但是构造SDI,需要从portType binding了解更多的信息.

JAX-RPC中说道:java接口的名字从wsdl:portType元素的name属性映射而来,如果使用wsdl:binding元素映射SDI,那么SDI的名字从wsdl:binding元素的name属性映射而来。

1.3.4Bindings

一个实现SDI的Stub类,类的名字为binding的name值+后缀”Stub”,它包含使用Axis Service和Call对象来进行方法的调用,它是一个远程服务的代理,以至于你可以把它当作本地对象来处理。另一方面,你不需要去处理endpont URL,namespace,或参数数组动态调用的问题,这个Stub隐藏了所有的工作并为你服务。

示例:

WSDL片段:

<binding name="AddressBookSOAPBinding"type="tns:AddressBook">
  ...
</binding>


生成的Stub类(片段):

public class AddressBookSOAPBindingStub extendsorg.apache.axis.client.Stub
    implementsAddressBook {
  publicAddressBookSOAPBindingStub() throws org.apache.axis.AxisFault {...}
 
  publicAddressBookSOAPBindingStub(URL endpointURL,
     javax.xml.rpc.Service service) throws org.apache.axis.AxisFault {...}
 
  publicAddressBookSOAPBindingStub(javax.xml.rpc.Service service)
      throwsorg.apache.axis.AxisFault {...}
 
  public voidaddEntry(String name, Address address)
      throwsRemoteException {...}
}


1.3.5 Services

通常,客户端程序不会直接示例化Stub,或示例化一个service locator并调用get方法返回一个Stub.这个locator通过WSDL中的service来生成,WSDL2Java通过service元素会生成两个对象,示例:

WSDL:

<service name="AddressBookService">
  <portname="AddressBook" binding="tns:AddressBookSOAPBinding">
   <soap:address location="http://localhost:8080/axis/services/AddressBook"/>
  </port>
</service>


WSDL2Java生成服务接口:

public interface AddressBookService extendsjavax.xml.rpc.Service {
  public StringgetAddressBookAddress();
 
  publicAddressBook getAddressBook() throws javax.xml.rpc.ServiceException;
 
  publicAddressBook getAddressBook(URL portAddress)
      throwsjavax.xml.rpc.ServiceException;
}


同时,生成locator来实现这个接口:

public class AddressBookServiceLocator extendsorg.apache.axis.client.Service
    implementsAddressBookService {
  ...
}


这个服务接口定义一个get方法获取每个在WSDL中定义的port ,locator实现这个服务接口,实现这些get方法。它可以获取Stub的实例。Service类会默认创建一个Stub,当你请求PortType的时候可能需要指定一个不同的URL。

下面给出一个典型的使用Stub类的示例:

public class Tester {
  public staticvoid main(String [] args) throws Exception {
    // Make aservice
   AddressBookService service = new AddressBookServiceLocator();
 
    // Now use theservice to get a stub which implements the SDI.
    AddressBookport = service.getAddressBook();
 
    // Make theactual call
    Address address= new Address(...);
   port.addEntry("Russell Butek", address);
  }
}


 

1.3.6 Server-side 绑定

Stub是Web Service在客户端的Java表示,一个skeleton是一个服务端的Java框架,为了生成skeleton类,你只需要指定在使用WSDL2Java的时候指定选项:” --server-side --skeletonDeploy true”,例:

% java -cp %AXISCLASSPATH%org.apache.axis.wsdl.WSDL2Java --server-side --skeletonDeploy trueWSDL-file-URL

会生成之前客户端所有的类,同时会生成一些新的文件:

WSDL clause

Java class(es) generated

For each binding

A skeleton class

An implementation template class


For all services

One deploy.wsdd file

One undeploy.wsdd file


如果你没有指定”—skeletonDeploy true”选项,skeleton将不会生成,deploy.wsdd中将直接通过实现类来进行发布。在这种情况下,deploy.wsdd包含描述实现类操作和参数的元数据,这种情况生成的文件如下;

WSDL clause

Java class(es) generated

For each binding

An implementation template class

For all services

One deploy.wsdd file with operation meta data

One undeploy.wsdd file


       这里我做了一个测试:就是想通过deploy.wsdd进行部署,但始终没有成功,后来发现,原来我一直都是在客户端项目中进行部署,这样是不会识别到相应的class的,所以一直出现ClassNotFoundException异常,必须将相应的java代码拷贝到服务端的项目中,然后再部署即可。通过这个测试可以了解到:之所以能将写好的class发布成Web Service依赖于当前所支持发布的环境及操作。我这里使用的是AdminClient进行发布,对象是相应的web应用,所以需要在WEB应用的支持下才能发布成Web Service。

上述发布和生成客户端代码及再次部署的过程类似于下图所示:

 

 

       上述过程可以看出,通过WSDL可以解耦客户端和服务端,首先编写好相应的WSDL,客户端通过WSDL生成调用代码,服务端通过WSDL生成模板服务代码和部署/解暑文件。同时客户端也可以生成模板服务代码,然后自己去写一些测试数据,通过调用测试数据来开展自己的工作,当服务端开发完后,只需要部署成Web Service即可,客户端再将相应调用代码修改为生成的客户端调用代码即可。更好的处理方法是:服务端对服务方法写一个mock,即填写模拟数据返回,然后发布服务,客户端调用这些服务,当服务端实现服务后,客户端可以不用做任何修改。

 


1.3.6.1 Skeleton Description(for Skeleton Deployment)

Skeleton类介于Axis引擎和服务实现类之间,它的名字为binding的name+后缀”Skeleton”,对于AddressBook binding,WSDL2Java生成如下:

public class AddressBookSOAPBindingSkeleton implementsAddressBook,
   org.apache.axis.wsdl.Skeleton {
  privateAddressBook impl;
 
  publicAddressBookSOAPBindingSkeleton() {
    this.impl = newAddressBookSOAPBindingImpl();
  }
 
  publicAddressBookSOAPBindingSkeleton(AddressBook impl) {
    this.impl =impl;
  }
 
  public voidaddEntry(java.lang.String name, Address address)
      throwsjava.rmi.RemoteException {
   impl.addEntry(name, address);
  }
}


真正的skeleton的内容比上面的更丰富,这里只是基本的信息。

Skeleton包含一个实现类

实现类模板描述

WSDL2Java生成的实现模板类如下:

public class AddressBookSOAPBindingImpl implementsAddressBook {
  public voidaddEntry(String name, Address address)
      throwsjava.rmi.RemoteException {
  }
}


这个模板通常被用来创建一个测试实现,它里面没有做任何事情。

WSDL2Java生成模板类的时候,当模板类不存在,则生成,当模板类存在,则不覆盖。

2.Java2WSDL

Java2WSDL工具通过java代码来生成WSDL,如果你对WSDL不太熟悉,你可以通过这种方式来生成WSDL

2.1步骤

2.1.1提供一个Java接口或类

编写和编译一个java接口(或类)来描述服务接口。例:

package samples.userguide.example6;
 
/**
 * Interfacedescribing a web service to set and get Widget prices.
 **/
public interface WidgetPrice {
  public voidsetWidgetPrice(String widgetName, String price);
  public StringgetWidgetPrice(String widgetName);
}


2.1.2使用Java2WSDL创建WSDL

例:

 

% java –cp %AXISCLASSPATH% org.apache.axis.wsdl.Java2WSDL-o wp.wsdl

   -l"http://localhost:8080/axis/services/WidgetPrice"

    -n  "urn:Example6"-p"samples.userguide.example6" "urn:Example6"

   samples.userguide.example6.WidgetPrice

·        -o indicates the name of the output WSDL file

·        -l indicates the location of the service

·        -n is the target namespace of theWSDL file

·        -p indicates a mapping from the package to anamespace. There may be multiple mappings.

·        the class specified contains the interface of thewebservice.

使用WSDL2Java创建绑定

% java –cp %AXISCLASSPATH% org.apache.axis.wsdl.WSDL2Java-o . -d Session -s -S true

    -Nurn:Example6samples.userguide.example6 wp.wsdl

将会生成以下文件:

·        WidgetPriceSoapBindingImpl.java : Java file containing the default server implementation of theWidgetPrice web service.
You will need to modify the *SoapBindingImpl file to add your implementation

·        WidgetPrice.java:New interface file that contains the appropriate java.rmi.Remote usages.

·        WidgetPriceService.java:Java file containing the client side service interface.

·        WidgetPriceServiceLocator.java: Java file containing the client side service implementationclass.

·        WidgetPriceSoapBindingSkeleton.java: Server side skeleton.

·        WidgetPriceSoapBindingStub.java: Client side stub.

·        deploy.wsdd:Deployment descriptor

·        undeploy.wsdd:Undeployment descriptor

·        (data types): Java fileswill be produced for all of the other types and holders necessary for the webservice. There are no additional files for the WidgetPrice web service.

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值