加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

CXF客户端动态调用--复杂类型参数传递

发布时间:2020-12-16 23:10:12 所属栏目:安全 来源:网络整理
导读:这几天在公司的项目中,需要调用第三方短信平台的webservice接口群发短信。走了许多弯路,最终解决了问题,并记下实践的一些经验。 在前一个项目中,为外界提供了一些webservice接口,使用的是apache-CXF,这个组件用的挺多的,但限制也是有的,例如它不能调

这几天在公司的项目中,需要调用第三方短信平台的webservice接口群发短信。走了许多弯路,最终解决了问题,并记下实践的一些经验。

在前一个项目中,为外界提供了一些webservice接口,使用的是apache-CXF,这个组件用的挺多的,但限制也是有的,例如它不能调用axis2 RPC模式的接口(网上的说法)。

在之前用它发布服务,和调用传递字符串入参等,都是很方便、简单。挺好用。但是最近调用短信平台接口出现的一些问题,还是感悟很深刻。

服务接口是用axis2发布的,需要调用的方法入参和返回参数都是pojo。

按照一贯的流程,使用wsdl2java工具生成代码,使用jax-ws proxy模式调用生成代理接口,封装好入参pojo参数,执行报异常。


java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.cxf.databinding.AbstractWrapperHelper.createWrapperObject(AbstractWrapperHelper.java:99)
at org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor.handleMessage(WrapperClassOutInterceptor.java:105)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:516)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:313)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:265)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:285)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:271)
at cn.intellisoft.hoorayos.webservice.client.DynamicClient.executeOperation(DynamicClient.java:39)
at cn.intellisoft.hoorayos.webservice.client.DynamicClient.main(DynamicClient.java:98)
2014-12-9 9:25:16 org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging
警告: Interceptor for {http://ws.apache.org/axis2}xxtInter#{http://ws.apache.org/axis2}Downsms has thrown exception,unwinding now
org.apache.cxf.interceptor.Fault
at org.apache.cxf.databinding.AbstractWrapperHelper.createWrapperObject(AbstractWrapperHelper.java:107)
at org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor.handleMessage(WrapperClassOutInterceptor.java:105)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:516)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:313)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:265)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:285)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:271)
at cn.intellisoft.hoorayos.webservice.client.DynamicClient.executeOperation(DynamicClient.java:39)
at cn.intellisoft.hoorayos.webservice.client.DynamicClient.main(DynamicClient.java:98)
Exception in thread "main" org.apache.cxf.interceptor.Fault
at org.apache.cxf.databinding.AbstractWrapperHelper.createWrapperObject(AbstractWrapperHelper.java:107)
at org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor.handleMessage(WrapperClassOutInterceptor.java:105)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:255)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:516)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:313)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:265)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:285)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:271)
at cn.intellisoft.hoorayos.webservice.client.DynamicClient.executeOperation(DynamicClient.java:39)
at cn.intellisoft.hoorayos.webservice.client.DynamicClient.main(DynamicClient.java:98)

还以为是CXF版本太低造成,换版本,依然异常。在网上,找了很多CXF客户端开发的blog、参考资料,几乎没有一篇可以将客户端传递复杂类型的技术讲得通透,大都是人云亦云、copy或是简单的字符串传递demo。

动态调用走不通,就使用jax-ws proxy,也是报异常。

由于接口使用了IP鉴权,怀疑是服务端没配置好,联系短信平台的客服和开发人员,进行一系列工作。首先服务端给的说明文档太坑人,文档太潦草,没有demo,还有部分错漏。这样的服务质量,汗!

后来,服务端开发人员给了一个小demo,axis2写的RPC客户端模式。

前面的方法都走不通,只好换框架组件为axis2。

换组件后,把之前用CXF工具生成的入参、返回参数pojo复制过来,包名为服务端接口入参的包名(看wsdl文件入参的namespace,可以翻译出来),去除所有jaxb注解(jaxb注解将pojo标注成xml schema)。

服务端开发人员给的axis2 RPC客户端模式代码:

public static void main(String[] args) throws AxisFault {
? ? ? ?RPCServiceClient serviceClient = new RPCServiceClient();
? ? ? ?Options options = serviceClient.getOptions();
? ? ? ?EndpointReference targetEPR = new EndpointReference("http://localhost:8088/services/smssevice");
? ? ? ?options.setTo(targetEPR);
? ? ? ? RequestMessage bean=new RequestMessage();//调用方法的入参
? ? ? ? Message head=new Message();
? ? ? ?head.setUserId("0001");
? ? ? ?head.setTimeStamp(new SimpleDateFormat("yyyyMMddHHmmssSSSS").format(new Date(System.currentTimeMillis())));
? ? ? ?head.setTransId("IT201412090000000000006");
? ? ? ? RequestMessageBody body=new RequestMessageBody();
? ? ? ?body.setContent("hello,短信测试。。。");
? ? ? ?body.setSmstype("4");
? ? ? ?body.setReceiveId("1");
? ? ? ?bean.setBODY(body);
? ? ? ?bean.setHEAD(head);
? ? ? ?Object[] opAddEntryArgs = new Object[] {bean};? ??
? ? ? ?Class[] classes = new Class[] {DownsmsResponseMessage.class};??
? ? ? ?QName opAddEntry = new QName("http://ws.apache.org/axis2","Downsms");? ?
? ? ? ?DownsmsResponseMessage beans=(DownsmsResponseMessage)serviceClient.invokeBlocking(opAddEntry,opAddEntryArgs,classes)[0];
? ? ? ?System.out.println(beans.getBODY().getRemark());
}

从前面的步骤到这里,短信发送功能正常了。

把正常demo(axis2的demo)的入参和返回参数pojo复制到CXF demo中,执行下面代码,不再报异常,OK,短信发送成功。

CXF客户端动态调用代码:(executeOperation方法疯转了动态调用的细节,这里就不列出,具体可以参考前面关于CXF动态调用的篇章)

public static void main(String[] args) throws Exception {
RequestMessage bean=new RequestMessage();//调用方法的入参
? ? ? ? Message head=new Message();
?? ? ? ?head.setUserId("0001");
?? ? ? ?head.setTimeStamp(new SimpleDateFormat("yyyyMMddHHmmssSSSS").format(new Date(System.currentTimeMillis())));
?? ? ? ?head.setTransId("IT201412090000000000006");
? ? ? ? RequestMessageBody body=new RequestMessageBody();
?? ? ? ?body.setContent("hello,短信测试。。。");
?? ? ? ?body.setSmstype("4");
?? ? ? ?body.setReceiveId("1");
?? ? ? ?bean.setBODY(body);
?? ? ? ?bean.setHEAD(head);

//动态调用
DownsmsResponseMessage respone = (DownsmsResponseMessage)executeOperation(getClient(SERVICE_URL),"Downsms",requestReport)[0];
System.out.println(respone.getBODY().getRemark());

}

-------------------------------

前面写了很多开发中的细节,本篇主要说明总结:

1,CXF动态调用,复杂类型参数的传递,参数POJO的schema(这里包含包名,继承关系,属性类型)一定要和服务端一样,而且一般要实现序列化Serializable,不然在和服务器连接正常的情况下会报参数类型异常。

2,还有注意IP鉴权,验证权限问题,需要和服务端人员了解清楚,细读对方给的接口说明文档(针对不同常见平台都会给demo)。

3,axis2组件有些情况比CXF强大,大多数商业平台使用的是axis2。

4,webservice调用最好选择和服务端组件相同,如axis2-->axis2,CXF-->CXF。

5,百度来的资料不一定好用。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读