简介
时隔多年,再次遇到需要调用WebService的业务,对方给予的wsdl说明文档还是内网的链接,并且设有基础访问权限,即在浏览器打开wsdl链接时需要输入【用户名+密码】登录后方可查看wsdl文档,这需要设置代理(我使用putty完成了代理),本文只记录使用org.apache.cxf调用wsdl的过程
https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html
org.apache.cxf
cxf-rt-frontend-jaxws
3.5.2
org.apache.cxf
cxf-rt-transports-http
3.5.2
/**
* 打开WSDL文件
* @return
*/
private static Bus openWSDL(){
Bus bus = BusFactory.getThreadDefaultBus();
bus.setExtension((name, address, httpConduit) -> {
//设置访问wsdl所需的用户名和密码
final AuthorizationPolicy authorization = new AuthorizationPolicy();
authorization.setUserName("username");
authorization.setPassword("password");
httpConduit.setAuthorization(authorization);
final HttpAuthSupplier supplier = new DefaultBasicAuthSupplier();
httpConduit.setAuthSupplier(supplier);
//设置service中location的映射代理IP和端口
final HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setProxyServer("127.0.0.1");
httpClientPolicy.setProxyServerPort(50000);
httpClientPolicy.setAllowChunking(false);
httpClientPolicy.setConnectionTimeout(50000);
httpClientPolicy.setReceiveTimeout(50000);
httpConduit.setClient(httpClientPolicy);
}, HTTPConduitConfigurer.class);
return bus;
}
/**
* 获取WSDL内容
* @return
*/
private static Map getWSDLContent() {
Map wsdl = new HashMap<>();
try {
Bus bus = openWSDL();
ClassLoader loader = Gmm1020Server.class.getClassLoader();
// 创建动态客户端
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(bus);
Client client = dcf.createClient("你的wsdl地址",
new QName("wsdl中的targetNamespace", "wsdl:service的name"),
loader,
new QName("wsdl中的targetNamespace", "HTTP_Port"));
QName qName = new QName("wsdl中的targetNamespace", "wsdl:operation的name");
List partInfos = client.getEndpoint()
.getService().getServiceInfos().get(0)
.getBinding(new QName("wsdl中的targetNamespace", "wsdl:binding的name"))
.getOperation(qName)
.getInput().getMessageParts();
wsdl.put("client",client);
wsdl.put("qname",qName);
wsdl.put("messagePartInfo",partInfos);
} catch (Exception e) {
throw new WebServiceException(e);
}
return wsdl;
}
Bus bus = openWSDL();
/**
* 调用远程过程
*/
public static void call(Map map) {
Map wsdl = getWSDLContent();
Client client = (Client) wsdl.get("client");
List partInfos = (List) wsdl.get("messagePartInfo");
QName qName = (QName) wsdl.get("qname");
String clazzName = partInfos.get(0).getTypeClass().getName();
try {
Object requestParamObject = Thread.currentThread().getContextClassLoader().loadClass(clazzName).newInstance();
Field[] fields = requestParamObject.getClass().getDeclaredFields();
for (Field field : fields) {
//如果是泛型
boolean b = field.getGenericType() instanceof ParameterizedType;
if(b && field.getType() == List.class){
Type[] types = ((ParameterizedType)field.getGenericType()).getActualTypeArguments();
for (Type type : types) {
Class aClass = (Class) type;
Object obj = aClass.newInstance();
List
List
class User {
private String userName;
private UserDetails userDetails;
}
代码层面:ParameterizedType
Type[] types = ((ParameterizedType)field.getGenericType()).getActualTypeArguments();
这个对象是一个接口,表示参数化类型,这句代码意思是返回这个field的实际类型参数
/**
* 字段写值
* @param obj
*/
private static void writeFiledVal(Object obj,Map param) {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
try {
field.set(obj,param.get(field.getName()));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
/**
* 测试使用
* 给字段写入自定义值
* @param obj
*/
private void writeCustomValue(Object obj) {
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if(!field.getType().isPrimitive()){
field.getType().getConstructors();
}
try {
field.set(obj,"1");
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
使用的时候,只需要讲你的入参对象转换成map,放入 'call()' 方法即可完成调用
响应结果虽然是服务器告诉我有问题(因为我的数据是乱写的),但是可以看得出来,调用是通了