上面的服务传递的是简单数据类型,返回的也是简单数据类型。下面我们用JavaBean 、List、Map、Array等返回值或参数完成WebService。
1、首先看看JavaBean模式的参数和返回值的WebService,JavaBean代码如下:
package com.hoo.entity; import java.io.Serializable; /** * function:User Entity * @author hoojo * @createDate Dec 16, 2010 10:20:02 PM * @file User.java * @package com.hoo.entity * @project AxisWebService * @blog http://blog.csdn.net/IBM_hoojo * @email [email protected] * @version 1.0 */ public class User implements Serializable { private static final long serialVersionUID = 677484458789332877L; private int id; private String name; private String email; private String address; //Constractor //getter、setter @Override public String toString() { return this.id + "#" + this.name + "#" + this.email + "#" + this.address; } }
没有上面特别就是一个普通的Java对象,里面提供一些属性及getter、setter方法和toString方法(在显示数据的时候有用),值 得注意的是在远程调用的Java对象都需要实现Serializable接口,这样在网络中传递对象的时候就不会出现重复的JavaBean。用过或是了 解EJB、RMI的朋友应该知道这点。序列化后的对象可以用io进行序列化写入到文件中,也可以反序列化解析到对象中的数据。
2、好,回正题。下面编写WebService的服务器端代码。
3、编写wsdd文本发布当前WebService,wsdd文件代码如下:
和上面的wsdd文件不同的是,这里多了beanMapping的配置。Qname是xml中规范限定名称,由命名空间url、本地名称、前缀组 成,本地名称是必需的且qname是不可变的。后面的myNSD(namespace)是必需的,是通过前面的qname指定的,myNSD后面的 urn:User就和程序中的QName对应的第一个参数,第二个参数对应配置文件中的qname的myNSD冒号后面的值。 languageSpecificType是javaBean的类路径。
4、发布WebService,还是允许命令行:
java -Djava.ext.dirs=lib org.apache.axis.client.AdminClient -lhttp://localhost:8080/AxisWebService/services/AdminService deployComplex.wsdd
发布后,在浏览器中请求:
http://localhost:8080/AxisWebService/servlet/AxisServlet
就可以看到发布的WebService和暴露的方法了。
5、客户端代码的编写,这次客户端和以前有些不一样。因为这里设置了参数和返回值都是复杂类型,而不是简单的类型了。代码如下:
package com.hoo.client; import java.rmi.RemoteException; import java.util.Date; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; import javax.xml.rpc.ParameterMode; import javax.xml.rpc.ServiceException; import org.apache.axis.client.Call; import org.apache.axis.client.Service; import org.apache.axis.encoding.XMLType; import org.apache.axis.encoding.ser.BeanDeserializerFactory; import org.apache.axis.encoding.ser.BeanSerializerFactory; import com.hoo.entity.User; /** * function:axis WebService传递复杂对象,客户端 * @author hoojo * @createDate Dec 16, 2010 10:32:57 PM * @file UserServiceClient.java * @package com.hoo.client * @project AxisWebService * @blog http://blog.csdn.net/IBM_hoojo * @email [email protected] * @version 1.0 */ @SuppressWarnings("unchecked") public class UserServiceClient { private static final String url = "http://localhost:8080/AxisWebService/services/ManagerUser"; private static Service service = new Service(); public static User getUser(String name) throws ServiceException, RemoteException { Call call = (Call) service.createCall(); call.setTargetEndpointAddress(url); QName qn = new QName("urn:User", "User"); //call.registerTypeMapping(User.class, qn, new BeanSerializerFactory(User.class, qn), new BeanDeserializerFactory(User.class, qn)); call.registerTypeMapping(User.class, qn, BeanSerializerFactory.class, BeanDeserializerFactory.class); call.setOperationName("getUserByName"); /* * 这里客户端和服务器端共用一个User,在实际开发中 * 客户端和服务器端在不同的机器上,所以User对象可能不一样 * 需要我们根据WebService的wsdl分析对象的属性 */ call.addParameter("name", XMLType.XSD_STRING, ParameterMode.IN); call.setReturnClass(User.class); User user = (User) call.invoke(new Object[] { "jackson" }); return user; } public static void setUser(User user) throws ServiceException, RemoteException { Call call = (Call) service.createCall(); call.setTargetEndpointAddress(url); //这里的QName的ns和wsdd文件中的对应 QName qn = new QName("urn:User", "User"); //这里是将对象序列化和反序列化的配置 call.registerTypeMapping(User.class, qn, new BeanSerializerFactory(User.class, qn), new BeanDeserializerFactory(User.class, qn)); call.setOperationName("setUser"); //设置参数类型 call.addParameter("user", qn, ParameterMode.IN); call.invoke(new Object[] { user }); } public static List
需要说明的是,这里传递的User和服务器端的User是同一个对象,在实际开发中应该不是同一个对象的。如java调用.net的WebService,传递的对象应该不是同一个。需要我们自己根据wsdl文件中的描述创建JavaBean。注意的是对象一个要序列化。
new QName("urn:User", "User")这里的QName的urn:User和wsdd文件中的对应,参数User也是和wsdd文件中的qname="myNSD:User" 对应的
这里是将对象序列化和反序列化的配置
call.registerTypeMapping(User.class, qn, new BeanSerializerFactory(User.class, qn), new BeanDeserializerFactory(User.class, qn));
User是Mapping的对象,也就是更加wsdl中参数描述创建的Java对象
call.addParameter("i", XMLType.XSD_INT, ParameterMode.IN);设置参数信息,ParameterMode.IN代表传递的参数,XMLType.XSD_INT,代表参数的类型,前面的i是参数名称
call.setReturnClass(User[].class);设置返回值的类型
特别说明:
A、 如果你调用的方法有返回值,一定要设置返回值的类型。call.setReturnClass
B、 如果你调用的方法有参数,一定要设置参数的类型call.addParameter
C、 记得添加wsdl4j.jar,序列化转换的时候需要用到,否则会出现找不到类型异常
运行后,效果如下:
客户端:
============getUser=============
41#jackson#[email protected]#china
============setUser=============
- No returnType was specified to the Call object! You must call setReturnType() if you have called addParameter().
============getUsers List=============
41#jack#0#[email protected]#china
41#jack#1#[email protected]#china
41#jack#2#[email protected]#china
41#jack#3#[email protected]#china
============setUsers List=============
- No returnType was specified to the Call object! You must call setReturnType() if you have called addParameter().
============getUserMap=============
{A=41#jack##[email protected]#china, B=41#tom#[email protected]#china}
============setUserMap=============
- No returnType was specified to the Call object! You must call setReturnType() if you have called addParameter().
============getUserArray=============
============setUserArray=============
- No returnType was specified to the Call object! You must call setReturnType() if you have called addParameter().
服务器端:
37#tom#[email protected]#china
37#jack#0#[email protected]#china
37#jack#1#[email protected]#china
37#jack#2#[email protected]#china
37#jack#3#[email protected]#china
{A=37#jack##[email protected]#china, B=37#tom#[email protected]#china}
37#jack#0#[email protected]#china
37#jack#1#[email protected]#china
37#jack#2#[email protected]#china
Map、Array、List、JavaBean都可以顺利转换,不管是参数还是返回值。怎么样,很简单吧!
传递内部类
如果你传递的JavaBean带有内部类,那么你的内部类需要是静态化的,且一样要序列化。为Account对象添加一个属性Birthday,Birthday是一个内部类,
package com.hoo.entity; import java.io.Serializable; /** * function:Account Entity * @author hoojo * @createDate Dec 16, 2010 10:18:20 PM * @file Account.java * @package com.hoo.entity * @project AxisWebService * @blog http://blog.csdn.net/IBM_hoojo * @email [email protected] * @version 1.0 */ public class Account { private int id; private String name; private String email; private String address; private Birthday birthday; public Birthday getBrithday() { return birthday; } public void setBrithday(Birthday birthday) { this.birthday = birthday; } //getter、setter @Override public String toString() { return this.id + "#" + this.name + "#" + this.email + "#" + this.address + "#" + this.birthday.getBirthday(); } /** * axis中传的的内部类一定要是静态的,且要序列化 */ public static class Birthday implements Serializable { private static final long serialVersionUID = 1L; private String bitthday; // getter、setter } }
同样我们需要在客户端调用的时候,注册类型序列化和反序列化。
QName qn = new QName("urn:Account", "entity.Account");
call.registerTypeMapping(Account.class , qn, new BeanSerializerFactory(Account.class , qn), new BeanDeserializerFactory(Account.class , qn));
QName qn2 = new QName("urn:Birthday", "Account.Birthday");
call.registerTypeMapping(Birthday.class , qn2, new BeanSerializerFactory(Birthday.class , qn2), new BeanDeserializerFactory(Birthday.class , qn2));
而在wsdd文件中和刚才几乎一样
作者:hoojo
出处: http://www.cnblogs.com/hoojo/archive/2010/12/20/1911380.html
blog:http://blog.csdn.net/IBM_hoojo