网站首页 > java教程 正文
CXF动态调用webservice
学习要点:
通过cxf动态(动态、动态、动态)调用webservice。参数涵盖多个普通形参、JavaBean、以及List集合的形式调用
会介绍调用的几个小技巧,结合fastjson和缓存知识完全掌控整个调用流程。
1.知识点汇总
常用的CXF调用WebService有以下几种方式:
1.动态调用webservice即不用生成客户端代码但是要调用复杂的webservice服务比较难实现,特别是调用.net的ws接口比较难
2.生成client java客户端代码然后通过java类来进行调用,如果在生成 wsdl的时候出错也是很难办的了,只有采用模拟请求soap的xml来调用了
详细信息可以参考上篇博文
Java动态调用复杂参数的WebService【精选汇总篇一】
2.核心代码(亲自实践,有问题可随时留言讨论)
网上铺天盖地打着动态调用的标题,但是点击去一看,失望而归,浪费了大量的时间。经过这2天的汇总,也算有个初步成果
调用参数涵盖多个普通形参、JavaBean、以及List集合的形式调用
首先说先网上常见的代码(最多的即是一个JaveBean的调用)我们先分析下,然后下面会提供一个比较全的封装方法。
常见代码如下:JavaBean的动态调用
private static String wsdlUrl="http://localhost:8001/demo/HelloServiceDemoUrl?wsdl"; // private static final QName SERVICE_NAME = new QName("namespace", "serviceName"); private static final QName SERVICE_NAME = new QName("http://service.limp.com/", "HelloServiceDemo"); /** * 网上流传的方法【初始化复杂,后续有改进版】 * @throws Exception */ public static void pojoInvokes()throws Exception{ // 创建动态客户端 JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance(); // 创建客户端连接 Client client = factory.createClient(wsdlUrl, SERVICE_NAME); ClientImpl clientImpl = (ClientImpl) client; Endpoint endpoint = clientImpl.getEndpoint(); // Make use of CXF service model to introspect the existing WSDL ServiceInfo serviceInfo = endpoint.getService().getServiceInfos().get(0); // 创建QName来指定NameSpace和要调用的service QName bindingName = new QName("http://service.limp.com/", "HelloServiceImplService"); BindingInfo binding = serviceInfo.getBinding(bindingName); //todo:?????????? // 创建QName来指定NameSpace和要调用的方法 QName opName = new QName("http://service.limp.com/", "getOrder"); BindingOperationInfo boi = binding.getOperation(opName); BindingMessageInfo inputMessageInfo = boi.getInput(); List<MessagePartInfo> parts = inputMessageInfo.getMessageParts(); // 取得对象实例 MessagePartInfo partInfo = parts.get(0); Class<?> partClass = partInfo.getTypeClass(); Object inputObject = partClass.newInstance(); // 取得字段的set方法并赋值 PropertyDescriptor partPropertyDescriptor = new PropertyDescriptor("id", partClass); Method userNoSetter = partPropertyDescriptor.getWriteMethod(); userNoSetter.invoke(inputObject, "no001todo"); // 调用客户端invoke()方法,把inputObject传递给要调用的方法并取得结果对象 Object[] result = client.invoke(opName, inputObject); // 取得的结果是一个对象 Class<?> resultClass = result[0].getClass(); // 取得返回结果的get方法并得到它的值 PropertyDescriptor resultDescriptor = new PropertyDescriptor("id", resultClass); Object resultGetter = resultDescriptor.getReadMethod().invoke(result[0]); System.out.println("result:" + resultGetter); // 取得返回结果的get方法并得到它的值 PropertyDescriptor tokenDescriptor = new PropertyDescriptor("id", resultClass); // 取得的是一个对象实例 Object getObj= tokenDescriptor.getReadMethod().invoke(result[0]); if("tokenGetter "!= null) { Class<?> resultTokenClass = tokenDescriptor.getReadMethod().invoke(result[0]).getClass(); // 得到对象实例下的***属性值 PropertyDescriptor expiredTimeDescriptor = new PropertyDescriptor("id", resultTokenClass); Object getter = expiredTimeDescriptor.getReadMethod().invoke(getObj); System.out.println("字段名:" + getter ); } }
分析:上面代码是我们很容易搜索到的,经过一些时间调试可以跑通(客户端不需要引入、创建任何的实体类,完全动态请求)
缺点:通过观察我们我们看到有几个问题
1.调用前 参数实例化(晕),这样是替换还不"累死”(玩笑!),需要改进。(下面代码会结合fastjson一步到位,轻松转化)
2.调用返回结果处理(??)又来一遍,必须要改进。
3.List集合、多个JavaBean....木有涉及,不全面
4.我们都知道cxf第一次创建请求时相当耗时的,如何优化??
3.整理后的部分通用代码
/** * * @param wsdlUrl wsdl的地址:http://localhost:8001/demo/HelloServiceDemoUrl?wsdl * @param methodName 调用的方法名称 selectOrderInfo * @param targetNamespace 命名空间 http://service.limp.com/ * @param name name HelloServiceDemo * @param paramList 参数集合 * @throws Exception */ public static String dynamicCallWebServiceByCXF(String wsdlUrl,String methodName,String targetNamespace,String name,List<Object> paramList)throws Exception{ //临时增加缓存,增加创建速度 if(!factoryMap.containsKey(methodName)){ // 创建动态客户端 JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance(); // 创建客户端连接 Client client = factory.createClient(wsdlUrl); ClientImpl clientImpl = (ClientImpl) client; Endpoint endpoint = clientImpl.getEndpoint(); factoryMap.put(methodName,endpoint); clientMap.put(methodName,client); System.out.println("初始化"); } //从缓存中换取 endpoint、client Endpoint endpoint=factoryMap.get(methodName); Client client=clientMap.get(methodName); // Make use of CXF service model to introspect the existing WSDL ServiceInfo serviceInfo = endpoint.getService().getServiceInfos().get(0); // 创建QName来指定NameSpace和要调用的service String localPart=name+"SoapBinding"; QName bindingName = new QName(targetNamespace, localPart); BindingInfo binding = serviceInfo.getBinding(bindingName); //创建QName来指定NameSpace和要调用的方法绑定方法 QName opName = new QName(targetNamespace, methodName);//selectOrderInfo BindingOperationInfo boi = binding.getOperation(opName); // BindingMessageInfo inputMessageInfo = boi.getInput(); BindingMessageInfo inputMessageInfo = null; if (!boi.isUnwrapped()) { //OrderProcess uses document literal wrapped style. inputMessageInfo = boi.getWrappedOperation().getInput(); } else { inputMessageInfo = boi.getUnwrappedOperation().getInput(); } List<MessagePartInfo> parts = inputMessageInfo.getMessageParts(); /***********************以下是初始化参数,组装参数;处理返回结果的过程******************************************/ Object[] parameters = new Object[parts.size()]; for(int m=0;m<parts.size();m++){ MessagePartInfo part=parts.get(m); // 取得对象实例 Class<?> partClass = part.getTypeClass();//OrderInfo.class; System.out.println(partClass.getCanonicalName()); // GetAgentDetails //实例化对象 Object initDomain=null; //普通参数的形参,不需要fastJson转换直接赋值即可 if("java.lang.String".equalsIgnoreCase(partClass.getCanonicalName()) ||"int".equalsIgnoreCase(partClass.getCanonicalName())){ initDomain=paramList.get(m).toString(); } //如果是数组 else if(partClass.getCanonicalName().indexOf("[]")>-1){ //转换数组 initDomain=JSON.parseArray(paramList.get(m).toString(),partClass.getComponentType()); }else{ initDomain=JSON.parseObject(paramList.get(m).toString(),partClass); } parameters[m]=initDomain; } //定义返回结果集 Object[] result=null; //普通参数情况 || 对象参数情况 1个参数 ||ArryList集合 try { result = client.invoke(opName,parameters); }catch (Exception ex){ ex.printStackTrace(); return "参数异常"+ex.getMessage(); } //返回调用结果 if(result.length>0){ return JSON.toJSON(result[0]).toString(); } return "invoke success, but is void "; }
改进分析:
1.调用参数初始化和返回结果初始化 利用fastjson快速实体化
2.借用缓存可以完成快速创建的效果(日后可以redis存放缓存结果,不知道有木有坑,可以共同讨论哈)
3.完全支持List集合、JavaBean、 多个(多个多个)参数.
/*************************main 测试代码***************************/
public static void main(String[] args) throws Exception{ /*********************参数初始化过程************************************/ String str="[{\"id\":\"NO.1\",\"money\":23},{\"id\":\"NO.2\",\"money\":24}]"; Object initDomain=JSON.parseArray(str,OrderInfo.class); // pojoInvokes1(); List<Object> listParam=new ArrayList<>(); String params="{\"id\":\"zhangsan\",\"money\":23}"; listParam.add(params); ////// List<Object> listParam2=new ArrayList<>(); String obj0="超级管理员"; String obj1="{\"id\":\"zhangsan\",\"money\":23}"; String obj2="{\"name\":\"one test\",\"intro\":\"这是订单详情\"}"; listParam2.add(obj0); listParam2.add(obj1); listParam2.add(obj2); ///// List<Object> listParam1=new ArrayList<>(); listParam1.add("zhangsan"); listParam1.add("lisi"); listParam1.add(6); ///// List<Object> listParam4=new ArrayList<>(); OrderInfo orderInfo1=new OrderInfo(); orderInfo1.setMoney(23); orderInfo1.setId("NO.1"); OrderInfo orderInfo2=new OrderInfo(); orderInfo2.setMoney(24); orderInfo2.setId("NO.2"); List listOrder=new ArrayList(); listOrder.add(orderInfo1); listOrder.add(orderInfo2); //[{"id":"NO.2","money":24},{"money":0}] listParam4.add(JSON.toJSON(listOrder).toString()); List<Object> listParam6=new ArrayList<>(); listParam6.add("北京"); /*********************方法动态调用测试************************************/ for(int i=0;i<2;i++){ Long start=System.currentTimeMillis(); //多个参数情况 System.out.println(dynamicCallWebServiceByCXF(wsdlUrl,"sayHello2", "http://service.limp.com/","HelloServiceDemo",listParam1)); //单个对象 System.out.println(dynamicCallWebServiceByCXF(wsdlUrl,"selectOrderInfo", "http://service.limp.com/","HelloServiceDemo",listParam)); //多个对象 System.out.println(dynamicCallWebServiceByCXF(wsdlUrl,"selectOrderInfoAndOrderDetail", "http://service.limp.com/","HelloServiceDemo",listParam2)); //集合测试 System.out.println(dynamicCallWebServiceByCXF(wsdlUrl,"getOrderList", "http://service.limp.com/","HelloServiceDemo",listParam4)); //net创建的webservice通过其他方式获取 // System.out.println(dynamicCallWebServiceByCXF("http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl","getSupportCity", // "http://WebXml.com.cn/","",listParam6)); Long end=System.currentTimeMillis(); System.out.println(i+"调用用时"+(end-start)); } }
结束语:有问题随时留言,共同讨论动态调用的坑
猜你喜欢
- 2024-10-16 第三方接口调用方案设计(第三方接口调用方式)
- 2024-10-16 java连接数据库的常见问题及解决办法
- 2024-10-16 Java Servlet实现Hessian接口调用
- 2024-10-16 Java调用外部程序的疑惑?(java调用外部类)
- 2024-10-16 Spring6.1新特性,四种方式调用REST接口(RestClient...)
- 2024-10-16 netty系列之:使用netty搭建websocket客户端
- 2024-10-16 Java 中的 Http 客户端 API:身份验证
- 2024-10-16 axis2客户端调用免费的webservice服务的实例
- 2024-10-16 程序员2022年你不懂RPC远程过程调用,RPC框架的话真的要被淘汰了
- 2024-10-16 K8S官方java客户端之五:proto基本操作
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)