前言:上一篇介绍了手动写客户端的axis1.4的应用实例,那个例子是没有问题的,但细心的同志们会发现,生成的wsdl文件是有问题的,比较刺眼的关键字是 ArrayOf_xsd_anyType 这个表明根本不认识list,而且list里放入的对象也没有在该WSDL文件里描述,这样带来的问题就是如果只根据WSDL文件来生成客户端,比如用axis1.4的wsdl2java命令
D:\develop_tools\axis-1_4\lib>java -cp .;axis.jar;jaxrpc.jar;saaj.jar;wsdl4j-1.5.1.jar;commons-discovery-0.2.jar;commons-logging-1.0.4.jar;log4j-1.2.8
.jar org.apache.axis.wsdl.WSDL2Java http://localhost:8091/bjchannel/services/EsopWBService1?wsdl
示例如上,的话,生成的类明显少了一个,就是list里放入的MenuNodeInterface类,这个在WSDL里根本没有体现
而且奇怪的是假如用list的话,如果添加了list的add方法,比如public void addMenuNodeInterface(MenuNodeInterface obj){list.add(obj);}(伪代码)的话,在生成的WSDL里就会有MenuNodeInterface的体现,但集合还是没有。这个看看AXIS的源码就明白了.
关于这个问题,首先参看axis1.4的官方文档user-guide.pdf,这个我在附件里上传上来,查看里面的
1.6.3里的1.6.3.1项,说的很清楚,由于LIST这些集合类和其他语言不通用,所以需要当作CUSTOM类自己做映射在service-config.xml里,那就麻烦了,加入实现类是ArrayList的话,还需要把相应的jar包加进来做映射;
所以后面有一句关键的:The most reliable way to send aggregate objects is to use arrays
有感觉没,对了,就是用[]数组来代替接口里需要的属性和返回值。
废话不说了,上代码
1:返回结果类
package com.asiainfo.boss.channel.channelservices;
import java.io.Serializable;
public class EsopResult1 implements Serializable{
/**
* seriaId
*/
private static final long serialVersionUID = -1922115715606536898L;
/**
* 0:成功
1:失败
*/
private Short returnCode=1;
//一般不用语言特定的集合类,统一用数组代替
//private List<MenuNodeInterface> sysMenuNodeList;
private MenuNodeInterface[] sysMenuNodeList;
private String errorMsg;
// public EsopResult1(){
// sysMenuNodeList=new ArrayList<MenuNodeInterface>();
// sysMenuNodeList.add(new MenuNodeInterface());
//
// }
//
public EsopResult1(){
sysMenuNodeList=new MenuNodeInterface[]{new MenuNodeInterface()};
}
public Short getReturnCode() {
return returnCode;
}
public void setReturnCode(Short returnCode) {
this.returnCode = returnCode;
}
// public List<MenuNodeInterface> getSysMenuNodeList() {
// return sysMenuNodeList;
// }
//
// public void setSysMenuNodeList(List<MenuNodeInterface> sysMenuNodeList) {
// this.sysMenuNodeList = sysMenuNodeList;
// }
//如果用list的话,还不光需要有list的set和get方法,还必须有addlist的方法,这样生成的wsdl才能包含list里的内容对象
//不过即使这样,还是会有问题,总之用数组代替就对了
public MenuNodeInterface[] getSysMenuNodeList() {
return sysMenuNodeList;
}
public void setSysMenuNodeList(MenuNodeInterface[] sysMenuNodeList) {
this.sysMenuNodeList = sysMenuNodeList;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
}
2:手动客户端调用测试类
package com.asiainfo.boss.channel.channelservices;
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.XMLType;
import org.apache.axis.encoding.ser.BeanDeserializerFactory;
import org.apache.axis.encoding.ser.BeanSerializerFactory;
public class EsopWBClient1 {
public static void main(String...args){
getResult();
}
public static void getResult(){
try {
String endpoint = "http://localhost:8091/bjchannel/services/EsopWBService1";
Long opId = new Long(1009);
Long orgId = new Long(1000);
Service service = new Service();
Call call = (Call) service.createCall();
QName qn = new QName("urn:EsopWBService1","EsopResult1");
QName qn1 = new QName("urn:EsopWBService1","MenuNodeInterface");
//注册 bean
call.registerTypeMapping(EsopResult1.class, qn,
new BeanSerializerFactory(EsopResult1.class, qn),
new BeanDeserializerFactory(EsopResult1.class, qn));
call.registerTypeMapping(MenuNodeInterface.class, qn1,
new BeanSerializerFactory(MenuNodeInterface.class, qn1),
new BeanDeserializerFactory(MenuNodeInterface.class, qn1));
call.setTargetEndpointAddress(new java.net.URL(endpoint));
call.setOperationName(new QName("EsopWBService1","qryMenuNodeInfoList"));
// Object[] sss=new Object[2];
// sss[0]=i1;
// sss[1]=i2;
//EsopResult1 ret = (EsopResult1) call.invoke("qryMenuNodeInfoList",new Object[]{i1,i2});
//以下两个参数必须加,不然后报数组越界异常,因为源码里的operation为的params需要手动设置
//invoke只负责往里传递数,不管原来方法参数的初始化,以下两句表明调用的方法需要初始化两个参数
call.addParameter("opId", XMLType.XSD_LONG, ParameterMode.IN);
call.addParameter("orgId", XMLType.XSD_LONG, ParameterMode.IN);
EsopResult1 ret = (EsopResult1) call.invoke(new Object[]{opId,orgId});
System.out.println("the operation result following:");
System.out.println("ErrorMsg = " + ret.getErrorMsg());
System.out.println("ReturnCode = " + ret.getReturnCode());
// 这是用list做属性的客户端写法,没有问题,问题只会出现在wsdl的生成上,因为手写客户端在前面手动
// 注册了list里的内容对象,所以会取到,但是生成的wsdl里是没有的,所以依赖wsdl的wsdl2java生成的
// 客户端程序就有问题了。
// System.out.println("MenuNodeList().size() = " + ret.getSysMenuNodeList().size());
// List<MenuNodeInterface> reList=ret.getSysMenuNodeList();
//以下是数组形式的调用
System.out.println("MenuNodeList().length = " + ret.getSysMenuNodeList().length);
MenuNodeInterface[] reList=ret.getSysMenuNodeList();
for(MenuNodeInterface mni : reList){
System.out.println("菜单名称:"+mni.getS_Caption());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
其他的类参照上一篇文章,没有修改
配置文件也没有任何变化
OK,附件是我用wsdl2java生成的客户端类,和自己写的测试调用类,打包上传了,老规矩,代码里的报名和有些配置名字自己修改,我就不去除了
参考文章
http://forums.sun.com/thread.jspa?threadID=5405862
http://www.javalobby.org/java/forums/t84343.html