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