Java如何动态的调用WebService?
一定时动态、动态、动态...不是动态就不是想要的解决方案。(本篇正在更新中..可以关注后,持续探讨)
一.方案汇总
网上查询的很多资料,零零散散没有找到一个比较满意的方案,特地汇总一下解决方案。
目前解决方案暂定为3种
1.利用cxf动态调用webservice
2.利用axis2的RPC方式调用webservice
3.利用HttpClient调用webservice
二.问题剖析
1.利用cxf动态调用webservice
查询资料后,首先说下cxf的解决方案。
1.1简单类型的动态调用如下
定义方法WebService方法:
package com.limp.service;
import com.limp.domain.OrderInfo;
import javax.jws.WebMethod;
import javax.jws.WebService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @intro :
* @auth : shinians
* @time : 2018/11/21 16:56
* @website: www.shinians.com
*/
@WebService
public interface HelloService {
/**
* 你好,webservice
* @param name
* @return
*/
@WebMethod
String sayHello(String name);
@WebMethod
String sayHello2(String name,String name2);
@WebMethod
String testMap(HashMap<String,String> param,String name);
@WebMethod
String testListMap(List<HashMap<String,String>>listMap);
/**
* 啊 遇到这个问题 就是Webservice不能传递Map类型的数据。
webservice可以处理String 基本数据类型,普通POJO、list 数组。
所以将map进行转换吧。
* @param mapOrder
* @return
*/
// @WebMethod
// String getMapOrder(Map<String,OrderInfo> mapOrder);
@WebMethod(action = "process")
String getOrder(OrderInfo order);
@WebMethod
String getOrderList(List<OrderInfo> orders);
}
以 String sayHello(String name)为例,调用方式如下(动态参数需要自行封装)。
/**
* 简单类型的调用(String):
*/
public static void SimpleInvoke(){
// 创建动态客户端
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient(wsdlUrl);
// 需要密码的情况需要加上用户名和密码
// client.getOutInterceptors().add(new ClientLoginInterceptor(USER_NAME,PASS_WORD));
Object[] objects = new Object[0];
try {
// invoke("方法名",参数1,参数2,参数3....);
objects = client.invoke("sayHello", "张三");
System.out.println("返回数据:" + objects[0]);
} catch (java.lang.Exception e) {
e.printStackTrace();
}
}
调用成功返回结果如下
1.2复杂对象形式调用
对于简单类型调用网上一搜到处都是解决方案,但是对于复杂对象形式传参如何解决呢?
以 String getOrder(OrderInfo order);方法为例
测试方法如下:
/**
* 对象传参
*/
public static void pojoInvoke(){
// 创建动态客户端
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient(wsdlUrl);
Object[] objects = new Object[0];
try {
//通过反射,创建OrderInfo对象,com.limp.service.OrderInfo 这个包名称必须和webservice的中的order路径一致
Object order = Thread.currentThread().getContextClassLoader().
loadClass("com.limp.service.OrderInfo").newInstance();
//初始化实体对象
Method m = order.getClass().getMethod("setId", String.class);
Method m1 = order.getClass().getMethod("setMoney", double.class);
Method m2 = order.getClass().getMethod("setOrderNo", String.class);
m.invoke(order, "uuid213-281heq-2131");
m1.invoke(order, 23);
m2.invoke(order, "NO110");
//开始调用
objects = client.invoke("getOrder", order);
System.out.println("调用对象形式参数返回数据:" + objects[0]);
} catch (java.lang.Exception e) {
e.printStackTrace();
}
}
java.lang.NoSuchMethodException: com.limp.service.OrderInfo.setMoney(java.lang.Double) -->将Double.class改成double.class总之时保持一致
这是网上搜到的一个解决方法,然则Thread.currentThread().getContextClassLoader().loadClass(“com.limp.service.OrderInfo") 这个com.limp.service.OrderInfo包路径你是怎么知道的呢,如果服务端是在另一个单位,这个路径你通过什么方法知道的呢,否则还是不能称为动态调用啊。(其他人的疑问,其实我也是这样疑问的,总之这还不是彻底的解决方案,算不上动态呀,但是,总归是能有调通的可能性)
对象调用扩展篇章如下(同时解决调用返回慢的问题)
还是以上面的为例。
参考下面这个两个例子(抱歉暂时没弄成功,先用其他方式弄)
http://cxf.apache.org/docs/dynamic-clients.html
https://bbs.csdn.net/topics/390797587
更新出炉,完全解决动态调用过程,包含多种情况处理,参考以下博文
博文链接:cxf动态调用webservice(参数包含多个形参、List集合、JAVABean对象)
net写的webservice用cxf调用会有问题。如下面链接
http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?op=getSupportDataSet
初步解决方案:采用其他的方式调用,如httpclient