通过WSDL生成客户端代码
来源:互联网 发布:迅捷网络路由器设置 编辑:程序博客网 时间:2024/06/06 02:47
目录
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.
- 通过WSDL生成客户端代码
- wsdl生成客户端代码
- 通过WSDL生成soap客户端代码时报的异常
- AXIS2实例3:通过wsdl生成服务和客户端代码
- 如何通过wsdl生成jax -ws客户端代码
- cxf 通过 wsdl 生成客户端
- 通过wsdl生成客户端命令
- wsdl生成客户端代码--wsimport
- axis2通过wsdl生成客户端程序
- Axis2+MyEclipse通过WSDL2Java生成wsdl客户端
- XFire使用WSDL生成客户端代码
- eclipse调用WSDL生成客户端代码
- Axis2;wsdl生成客户端和serverJava代码
- axis2根据wsdl生成客户端代码
- cmd下生成wsdl客户端代码指令
- Axis2;wsdl生成客户端和serverJava代码
- wsdl cmd下生成客户端代码
- Webservice 之.wsdl 生成客户端代码
- POJ2724
- 时间换算(java)
- LeetCode 36. Valid Sudoku
- Qt之QSystemTrayIcon
- 浅析java一些修饰符
- 通过WSDL生成客户端代码
- 一个低概率core dump问题的定位------打印log时访问了长度为0的vector
- 一些关于HTML与CSS的总结与实际应用
- CSS——背景属性
- vim的一些使用技巧
- 阶段总结(工作)
- 简单dp算法——Cow Bowling
- 【转】同步通信与异步通信的区别
- 浏览器中调试web你知道吗?