4 服务发布需要注意的地方(包括客户端和服务端)
axis的用法可以说简单,也可以说难。有很多细节方面不注意的话会让你花费很多时间。很多答案在网上是没有答案的,只能靠自己琢磨。在这一节中我就把一些常见的问题或建议总结下:
1.自定义类型的映射。
QName qn = new QName("urn:BeanService", "AbstractServiceinfo"); _call.registerTypeMapping(AbstractServiceinfo.class, qn, new org.apache.axis.encoding.ser.BeanSerializerFactory( AbstractServiceinfo.class, qn), new org.apache.axis.encoding.ser.BeanDeserializerFactory( AbstractServiceinfo.class, qn));
格式基本如上所示。
一定要记住当你的方法需要传入自定义类型的参数或返回自定义类型时,一定要在wsdd文档中注册,在客户端编程时也要注册。
客户端采取第二种方式时的映射注册可以看3.2.3的代码,采取第一种方式时也要注册,需要找到服务对应的存根类SN_AdvanceSearchSoapBindingStub,在这个类里有各个方法对应的调用配置,找到需要注册的方法,加上上面的映射就行了。格式都是一样的!
2.当返回类型类似于ArrayList<Serviceinfo>时
对于这样的返回类型,axis都会把返回值转成Object[],别想着直接把结果转成ArrayList,有时会出问题
下面是一个典型的用法:方法的返回值是ArrayList<Serviceinfo>,用下面的方法遍历就行了。
Object[] result = (Object[]) call.invoke(new Object[] { search }); if (result != null && result.length > 0) { for (int i = 0; i < result.length; i++) { Serviceinfo serviceinfo = (Serviceinfo) result[i]; System.out.println(serviceinfo.getCatagoryName() + serviceinfo.getAffiliation()); } }
对于java中的set也一样,都会转成Object[],如下面的方法:
Map<Integer, Set<Integer>> composition(UserParameter userparameter)得到返回值时就应该这样处理:
Map<Integer, Object[]> result=(Map) call.invoke(new Object[]{userPar}); for (Iterator<Integer> iter = result.keySet().iterator(); iter .hasNext();) { Integer key = iter.next(); Object[] obj = result.get(key); if(obj != null && obj.length > 0) { for(int i = 0; i < obj.length; i ++) { Integer serviceinfo = (Integer) obj[i]; System.out.println(serviceinfo); } }
注意对应于Set<Integer>的返回值是Object[]类型,通过循环来遍历,如果直接转型就会出现异常。
3.自定义类型一定要可以序列化,也就是要实现java.io.Serializable接口。如果你的方法准备发布成web服务最好把输入和输出都打包成javaBean,axis对javaBean的处理还是很自动的。
4.需要在服务端和客户端传递的javaBean当然在两端的工程里都应该有相似的代码,否则就会出现一方不能解析!如果客户端不能直接拿到javaBean的代码,可以借助wsdl2java生成的类中就应该会有对应的javaBean,直接拿过来用就行,当然,下一步采取哪种方式调用服务都是随意的。可见wsdl2java还是很有用的。
5.这点一定要看:血的教训
如果你的服务中返回值都是类似于List<Serviceinfo> getServiceinfoList(...)这样的集合类型,而没有一个类似于Serviceinfo getServiceinfo(..)这样的方法,发布成服务后,在对应的wsdl中就不会出现Serviceinfo的复杂类型对应的,也就是说你用wsdl2java是不能生成Serviceinfo对应的javaBean的。。调用的时候也就会出错。解决方法是在服务端可以加上一个什么也不做的public方法,如:
public Serviceinfo doNothing(){ Serviceinfo info=new Serviceinfo(); return info; }
这样。wsdl文档中就会有对Serviceinfo的类型定义了。
这一步很重要啊。。当时在这徘徊了好久。。一定不要以为你在wsdd中有了beanMapping定义,就会在wsdl中出现对应类型定义,一定要在你的public方法的输入或返回值用到这个bean时才会在wsdl中定义!
还碰到好多问题,一时想不起来,想到后再补充吧。
最后看看一些参考文献:
1.Web_Service开发指南_2.3.1.pdf,新手建议先看这个。。比我写的好多了!可以到这个网下:
2.axis 生成客户端client stub文件
http://hi.baidu.com/shanshuijoy/blog/item/6766673e4d2a1e3570cf6cf9.html
3.AXIS实现Web服务深入篇
http://g.51cto.com/michael/323
4.axis开发web服务
http://yangzb.iteye.com/blog/256890