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("/", "HelloServiceDemo");
/**
* 网上流传的方法【初始化复杂,后续有改进版】
* @throws Exception
*/
public static void pojoInvokes()throws Exception{
// 创建动态客户端
JaxWsDynamicClientFactory factory = ();
// 创建客户端连接
Client client = (wsdlUrl, SERVICE_NAME);
ClientImpl clientImpl = (ClientImpl) client;
Endpoint endpoint = ();
// Make use of CXF service model to introspect the existing WSDL
ServiceInfo serviceInfo = ().getServiceInfos().get(0);
// 创建QName来指定NameSpace和要调用的service
QName bindingName = new QName("/", "HelloServiceImplService");
BindingInfo binding = (bindingName);
//todo:?????????? // 创建QName来指定NameSpace和要调用的方法
QName opName = new QName("/", "getOrder");
BindingOperationInfo boi = (opName);
BindingMessageInfo inputMessageInfo = ();
List<MessagePartInfo> parts = ();
// 取得对象实例
MessagePartInfo partInfo = (0);
Class<?> partClass = ();
Object inputObject = ();
// 取得字段的set方法并赋值
PropertyDescriptor partPropertyDescriptor = new PropertyDescriptor("id", partClass);
Method userNoSetter = ();
(inputObject, "no001todo");
// 调用客户端invoke()方法,把inputObject传递给要调用的方法并取得结果对象
Object[] result = (opName, inputObject);
// 取得的结果是一个对象
Class<?> resultClass = result[0].getClass();
// 取得返回结果的get方法并得到它的值
PropertyDescriptor resultDescriptor = new PropertyDescriptor("id", resultClass);
Object resultGetter = ().invoke(result[0]);
("result:" + resultGetter);
// 取得返回结果的get方法并得到它的值
PropertyDescriptor tokenDescriptor = new PropertyDescriptor("id", resultClass);
// 取得的是一个对象实例
Object getObj= ().invoke(result[0]);
if("tokenGetter "!= null) {
Class<?> resultTokenClass = ().invoke(result[0]).getClass();
// 得到对象实例下的***属性值
PropertyDescriptor expiredTimeDescriptor = new PropertyDescriptor("id", resultTokenClass);
Object getter = ().invoke(getObj);
("字段名:" + getter );
}
}
分析:上面代码是我们很容易搜索到的,经过一些时间调试可以跑通(客户端不需要引入、创建任何的实体类,完全动态请求)
缺点:通过观察我们我们看到有几个问题
1.调用前 参数实例化(晕),这样是替换还不"累死”(玩笑!),需要改进。(下面代码会结合fastjson一步到位,轻松转化)
2.调用返回结果处理(??)又来一遍,必须要改进。
集合、多个JavaBean....木有涉及,不全面
4.我们都知道cxf第一次创建请求时相当耗时的,如何优化??
3.整理后的部分通用代码
/**
*
* @param wsdlUrl wsdl的地址:http://localhost:8001/demo/HelloServiceDemoUrl?wsdl
* @param methodName 调用的方法名称 selectOrderInfo
* @param targetNamespace 命名空间 /
* @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(!(methodName)){
// 创建动态客户端
JaxWsDynamicClientFactory factory = ();
// 创建客户端连接
Client client = (wsdlUrl);
ClientImpl clientImpl = (ClientImpl) client;
Endpoint endpoint = ();
(methodName,endpoint);
(methodName,client);
("初始化");
}
//从缓存中换取 endpoint、client
Endpoint endpoint=(methodName);
Client client=(methodName);
// Make use of CXF service model to introspect the existing WSDL
ServiceInfo serviceInfo = ().getServiceInfos().get(0);
// 创建QName来指定NameSpace和要调用的service
String localPart=name+"SoapBinding";
QName bindingName = new QName(targetNamespace, localPart);
BindingInfo binding = (bindingName);
//创建QName来指定NameSpace和要调用的方法绑定方法
QName opName = new QName(targetNamespace, methodName);//selectOrderInfo
BindingOperationInfo boi = (opName);
// BindingMessageInfo inputMessageInfo = ();
BindingMessageInfo inputMessageInfo = null;
if (!()) {
//OrderProcess uses document literal wrapped style.
inputMessageInfo = ().getInput();
} else {
inputMessageInfo = ().getInput();
}
List<MessagePartInfo> parts = ();
/***********************以下是初始化参数,组装参数;处理返回结果的过程******************************************/
Object[] parameters = new Object[()];
for(int m=0;m<();m++){
MessagePartInfo part=(m);
// 取得对象实例
Class<?> partClass = ();//;
(()); // GetAgentDetails
//实例化对象
Object initDomain=null;
//普通参数的形参,不需要fastJson转换直接赋值即可
if("".equalsIgnoreCase(())
||"int".equalsIgnoreCase(())){
initDomain=(m).toString();
}
//如果是数组
else if(().indexOf("[]")>-1){
//转换数组
initDomain=((m).toString(),());
}else{
initDomain=((m).toString(),partClass);
}
parameters[m]=initDomain;
}
//定义返回结果集
Object[] result=null;
//普通参数情况 || 对象参数情况 1个参数 ||ArryList集合
try {
result = (opName,parameters);
}catch (Exception ex){
();
return "参数异常"+();
}
//返回调用结果
if(>0){
return (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=(str,);
// pojoInvokes1();
List<Object> listParam=new ArrayList<>();
String params="{\"id\":\"zhangsan\",\"money\":23}";
(params);
//
List<Object> listParam2=new ArrayList<>();
String obj0="超级管理员";
String obj1="{\"id\":\"zhangsan\",\"money\":23}";
String obj2="{\"name\":\"one test\",\"intro\":\"这是订单详情\"}";
(obj0);
(obj1);
(obj2);
/
List<Object> listParam1=new ArrayList<>();
("zhangsan");
("lisi");
(6);
/
List<Object> listParam4=new ArrayList<>();
OrderInfo orderInfo1=new OrderInfo();
(23);
("NO.1");
OrderInfo orderInfo2=new OrderInfo();
(24);
("NO.2");
List listOrder=new ArrayList();
(orderInfo1);
(orderInfo2);
//[{"id":"NO.2","money":24},{"money":0}]
((listOrder).toString());
List<Object> listParam6=new ArrayList<>();
("北京");
/*********************方法动态调用测试************************************/
for(int i=0;i<2;i++){
Long start=();
//多个参数情况
(dynamicCallWebServiceByCXF(wsdlUrl,"sayHello2", "/","HelloServiceDemo",listParam1));
//单个对象
(dynamicCallWebServiceByCXF(wsdlUrl,"selectOrderInfo", "/","HelloServiceDemo",listParam));
//多个对象
(dynamicCallWebServiceByCXF(wsdlUrl,"selectOrderInfoAndOrderDetail", "/","HelloServiceDemo",listParam2));
//集合测试
(dynamicCallWebServiceByCXF(wsdlUrl,"getOrderList", "/","HelloServiceDemo",listParam4));
//net创建的webservice通过其他方式获取
// (dynamicCallWebServiceByCXF("/WebServices/?wsdl","getSupportCity",
// "/","",listParam6));
Long end=();
(i+"调用用时"+(end-start));
}
}
结束语:有问题随时留言,共同讨论动态调用的坑
可以加群讨论
点击链接加入群聊【Java技术交流群-LP框架】369022804:/?_wv=1027&k=5QHnbNE