cxf动态调用webservice(参数包含多个形参、List集合、JAVABean对象)

                                              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));
		}
	}

结束语:有问题随时留言,共同讨论动态调用的坑

可以加群讨论

点击链接加入群聊【Java技术交流群-LP框架】369022804:https://jq.qq.com/?_wv=1027&k=5QHnbNE 

 

相关推荐
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付 9.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值