soapui是一个webservice的测试工具。他提供图形界面编辑soap格式的数据然后post到服务端,返回soap数据,
阅读以下他的源码以后可以利用的这个工具来做一个调用webservice的动态客户端。
虽然说现在webservice的客户端调用比较方便,axis的话可以利用eclipse插件建一个webservice client代码自动生成,cxf 也可以利用wsdl2java生成客户端。
但是这2种方式都避免不了需要构建class加载到classloader里面,如果一个应用需要调用大量的webservice的话,那么这些class的数量相当可观,应用也因为webservice而庞大起来。
那么利用SOAPUI 写一个动态客户端,说白了就是构建soap数据,利用httpclient 发送 soap数据,处理返回soap数据。
直接上代码剖析:
jar包列表(soapui不是省油的灯,依赖的jar确实不少,删减了好多才找到减少到这么多),ps:如果肯下狠心把内容提取一下应该不错,可惜没有那个魄力了。
博客不能上传jar包,分享代码容量也不够,可惜~~。
首先编写帮助类,利用SOAPUI 获取需要执行的webservice的信息
package com.test.share.soapui;
import java.io.IOException;
import org.apache.xmlbeans.XmlException;
import com.eviware.soapui.impl.WsdlInterfaceFactory;
import com.eviware.soapui.impl.wsdl.WsdlInterface;
import com.eviware.soapui.impl.wsdl.WsdlOperation;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
import com.eviware.soapui.support.SoapUIException;
/**
*
* @author fat_tian
*
*/
public class SoapUIHelper {
/**
* 获取webservice信息类
* @param wsdl
* @param opName
* @return
* @throws SoapUIException
* @throws XmlException
* @throws IOException
*/
public static WsdlOperation getWsdlFace(String wsdl,String opName) throws SoapUIException, XmlException, IOException{
//根据wsdl地址获取接口
WsdlInterface[] facesInfo=WsdlInterfaceFactory.importWsdl(new WsdlProject(), wsdl, false);
if(facesInfo!=null&&facesInfo.length>0){
// 根据接口获取方法
for(WsdlInterface wface: facesInfo){
//获取soap1.1的吧~
if(SoapVersion.Soap11.equals(wface.getSoapVersion())){
WsdlOperation op =wface.getOperationByName(opName);
return op;
}
}
}
return null;
}
}
好,接下来就是webservice执行器
package com.test.share.soapui;
import java.util.Date;
import javax.wsdl.BindingOperation;
import javax.wsdl.Definition;
import org.apache.commons.lang.StringUtils;
import com.eviware.soapui.impl.wsdl.WsdlInterface;
import com.eviware.soapui.impl.wsdl.WsdlOperation;
import com.eviware.soapui.impl.wsdl.WsdlRequest;
import com.eviware.soapui.impl.wsdl.WsdlSubmit;
import com.eviware.soapui.impl.wsdl.WsdlSubmitContext;
import com.eviware.soapui.impl.wsdl.support.soap.SoapMessageBuilder;
import com.eviware.soapui.model.iface.Response;
import com.eviware.soapui.model.iface.SubmitContext;
/**
*
* @author fat_tian
*
*/
public class SoapUIExecutor {
private SoapProxy proxy;
public SoapUIExecutor(SoapProxy proxy){
this.proxy=proxy;
}
/**
* 通过SOAPUI 获取到需要调用webservice信息
* @param wsdl
* @param opName 方法名
* @return
* @throws Exception
*/
private WsdlOperation getWsdlOperation(String wsdl,String opName) throws Exception{
WsdlOperation wop=SoapUIHelper.getWsdlFace(wsdl, opName);
return wop;
}
/**
* 执行webservice
* 执行顺序逻辑:
* doBefore执行前-->parsePostData数据转换-->submitData提交--parseRtnData数据转化-->doAfter执行后
*/
public String processWs(String wsdl,String opName){
try{
// 执行前搞些啥~~
doBefore();
// 获取执行方法信息
WsdlOperation op=getWsdlOperation(wsdl, opName);
if(op==null){
throw new Exception("operante is null~");
}
// 获取soap格式数据
String opData=getDataTemplate(op);
if(StringUtils.isEmpty(opData)){
throw new Exception("soap data is null ~");
}
// 对soap格式数据进行数据填充之类。。。
opData =parsePostData(opData);
// 提交数据(执行webservice了)
String response =submitData(opData, op);
// 处理返回数据
response=parseRtnData(response);
// 执行后搞些啥~~
doAfter();
return response;
}catch (Exception e) {
// TODO: handle exception
doError(e);
}finally{
}
return null;
}
private String submitData(String opData,WsdlOperation operation) throws Exception{
WsdlRequest request=operation.addNewRequest("ws_"+new Date().getTime());
SubmitContext context = new WsdlSubmitContext(request);
request.setRequestContent(opData);
WsdlSubmit<WsdlRequest> submit = (WsdlSubmit<WsdlRequest>) request
.submit(context, false);
Response response = submit.getResponse();
// 获取了返回的输出参数的XML
String resData = response.getContentAsString();
return resData;
}
private String getDataTemplate(WsdlOperation operation) throws Exception{
//获取webservice 接口
WsdlInterface face= operation.getInterface();
// 获取到soap数据的builder
SoapMessageBuilder builder = face.getMessageBuilder();
Definition definition = face.getWsdlContext().getDefinition();
// 找到方法
BindingOperation bo = operation.findBindingOperation(definition);
// 构建soap格式数据。。。
String soapData = builder.buildSoapMessageFromInput(bo, true, true);
return soapData;
}
private String parsePostData(String soapTemplate){
//这里可以对这个xml进行操作~从而达到赋值的效果,这里需要下手写多点代码了做数据绑定
//让代理去搞
return proxy.parsePostData(soapTemplate);
}
private String parseRtnData(String data){
// 这里可以对返回值进行处理,组装符合业务需求的xml
//让代理去搞
return proxy.parseRtnData(data);
}
private void doBefore(){
//让代理去搞
proxy.doBefore();
};
private void doAfter(){
//..
proxy.doAfter();
}
private void doError(Exception e){
//...
proxy.doError(e);
}
}
下面贴个简单的代理类,这个代码如果可以做数据绑定的话将会是一个强大的代理类哦~
package com.test.share.soapui;
/**
* 执行soap的一个代理
* @author fat_tian
*
*/
public class SoapProxy {
public String parsePostData(String soapTemplate) {
System.out.println(soapTemplate);
return soapTemplate;
}
public String parseRtnData(String data) {
System.out.println(data);
return data;
}
public void doBefore() {
System.out.println(" doBefore~ ");
};
public void doAfter() {
System.out.println(" doAfter~ ");
};
public void doError(Exception e) {
System.out.println(e.getMessage());
};
}
ok,以上就完成了整个执行的类,下面简单调用一个天气预报的webservice来做尝试
package com.test.share.soapui;
public class Test {
public static void main(String[] args) throws Exception {
SoapUIExecutor exec = new SoapUIExecutor(new SoapProxy());
String rtn = exec
.processWs(
"http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl",
"getSupportProvince");
}
}