使用过soapUI开发工具的同学都知道,根据wsdl地址可以生成基于soap1.1协议和soap1.2协议两个版本的soap请求报文,便于开发或测试人员进行接口测试,不过遗憾的是不能对wsdl进行批量解析生成请求报文。基于此,本文在soapui源码的基础进行了二次开发,增加了对wsdl的批量解析。并且集成了mybatis,对mysql或oracle数据库进行读写操作,便于存储解析后的报文等信息。源码已上传至github,若需要请前往阅读和下载,有帮助顺便送上小星星哦!感谢!
一、需求背景
(一)soap报文格式修改:通常情况下,使用soapUI生成的请求报文标签之间是用“?”填充的,而根据业务需求,需要将其替换成“${标签名}”,譬如说由原来的“<xsd:bankCode>?</xsd:bankCode>"修改为“<xsd:bankCode>${bankCode}</xsd:bankCode>";其次,soapUI生成的请求报文具有一定的格式(换行、空格),所以将不必要的内容进行删除,包括无用的注释等信息,以免占用空间。
(二)批量解析wsdl文档:若是业务量不多,使用soapUI生成报文,然后手动修改即可,不过现在的业务量较大,需要对几百个wsdl进行解析,所以需要对源码进行修改,添加和封装来解决批量解析的问题。
(三)持久化数据库:最后需要对解析后的报文存储到数据库,以便后续开发使用。
二、代码简介
(一)soap报文格式修改
首先解决第一个需求,这部分可以定位到soapui源码com.eviware.soapui.impl.wsdl.support.xsd.SampleXmlUtil工具类。分析源码可知,其主要思想就是将wsdl文档中的标签元素解析出来后,在标签之间插入“?”。因此将processElement()方法中解析出来的标签元素element.getName().getLocalPart()声明为全局变量myElement,然后将“?”替换成“${myElement}”即可,具体详见我的源码,点击SampleXmlUtil。
(二)批量解析wsdl文档
为了方便解析wsdl,所以在soapui源码的基础上二次开发,新增加了一个工具包com.founder.soapui,用来封装和解析wsdl。
1 package com.founder.soapui; 2 import com.eviware.soapui.impl.wsdl.WsdlOperation; 3 /** 4 * @author :Mark Wang 5 * @date :Created in 07/05/2020 10:07:06 6 * @description: Encapsulates the necessary information of WsdlOperation 7 * @modified By: 8 * @version: 1.0 9 */ 10 public class OperationInfo { 11 private String operationName; 12 private String requestXml; 13 private String responseXml; 14 15 public OperationInfo(WsdlOperation operation) { 16 operationName = operation.getName(); 17 requestXml = operation.createRequest( true ); 18 responseXml = operation.createResponse(true); 19 } 20 }
1 package com.founder.soapui; 2 import com.eviware.soapui.impl.wsdl.WsdlInterface; 3 import com.eviware.soapui.impl.wsdl.WsdlOperation; 4 import java.util.ArrayList; 5 import java.util.List; 6 /** 7 * @author :Mark Wang 8 * @date :Created in 07/05/2020 10:07:06 9 * @description: Encapsulates the necessary information of WsdlInterface 10 * @modified By: 11 * @version: 1.0 12 */ 13 public class InterfaceInfo { 14 private String interfaceName; 15 private List<OperationInfo> operations; 16 private String[] address; 17 18 public InterfaceInfo(WsdlInterface wsdlInterface) { 19 this.interfaceName = wsdlInterface.getName(); 20 this.address = wsdlInterface.getEndpoints(); 21 int operationNum = wsdlInterface.getOperationCount(); 22 List<OperationInfo> operations = new ArrayList<OperationInfo>(); 23 24 for(int i = 0; i < operationNum; i++) { 25 WsdlOperation operation = ( WsdlOperation )wsdlInterface.getOperationAt( i ); 26 OperationInfo operationInfo = new OperationInfo(operation); 27 operations.add(operationInfo); 28 } 29 this.operations = operations; 30 } 31 }
1 package com.founder.soapui; 2 import com.eviware.soapui.impl.wsdl.WsdlInterface; 3 import com.eviware.soapui.impl.wsdl.WsdlProject; 4 import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlImporter; 5 import java.util.ArrayList; 6 import java.util.List; 7 /** 8 * @author :Mark Wang 9 * @date :Created in 07/05/2020 10:07:06 10 * @description: Load information according to wsdl location 11 * @modified By: 12 * @version: 1.0 13 */ 14 public class WsdlInfo { 15 private String wsdlName; 16 private List<InterfaceInfo> interfaces; 17 18 public WsdlInfo(String path) throws Exception { 19 WsdlProject project = new WsdlProject(); 20 WsdlInterface[] wsdlInterfaces = WsdlImporter.importWsdl( project, path ); 21 this.wsdlName = path; 22 if(null != wsdlInterfaces) 23 { 24 List<InterfaceInfo> interfaces = new ArrayList<InterfaceInfo>(); 25 for(WsdlInterface wsdlInterface : wsdlInterfaces) 26 { 27 InterfaceInfo interfaceInfo = new InterfaceInfo(wsdlInterface); 28 interfaces.add(interfaceInfo); 29 } 30 this.interfaces = interfaces; 31 } 32 } 33 }
1 package com.founder.soapui; 2 import java.util.ArrayList; 3 import java.util.List; 4 /** 5 * @author :Mark Wang 6 * @date :Created in 07/05/2020 10:07:06 7 * @description: Batch parsing WSDL to generate request message 8 * @modified By: 9 * @version: 1.0 10 */ 11 public class BatchWsdlParse { 12 private static List<String> soapRequest = new ArrayList<>(); 13 14 /** 15 * Parsing WSDL to get request message 16 * @param wsdlLocation 17 * @return 18 * @throws Exception 19 */ 20 public static List<String> wsdlParse (String wsdlLocation) throws Exception { 21 WsdlInfo wsdlInfo = new WsdlInfo(wsdlLocation); 22 for (InterfaceInfo interfaceInfo : wsdlInfo.getInterfaces()) { 23 soapRequest.add(parseInterfaceInfo (interfaceInfo)); 24 } 25 return soapRequest; 26 } 27 28 /** 29 * Batch wsdl parse 30 * @param String 31 * @return 32 * @throws Exception 33 */ 34 public static List<String> batchWsdlParse (List<String> wsdlList) throws Exception { 35 for (WsdlUrl wsdlUrl : wsdlList) { 36 WsdlInfo wsdlInfo = new WsdlInfo(wsdlUrl); 37 for (InterfaceInfo interfaceInfo : wsdlInfo.getInterfaces()) { 38 soapRequest.add(parseInterfaceInfo (interfaceInfo)); 39 } 40 } 41 return soapRequest; 42 } 43 44 /** 45 * parse InterfaceInfo 46 * @param interfaceInfo 47 * @param serviceId 48 * @return 49 */ 50 public static String parseInterfaceInfo (InterfaceInfo interfaceInfo) { 51 return interfaceInfo.getOperations().get(0).getRequestXml(); 52 } 53 }
1 /** 2 * @author :Mark Wang 3 * @date :Created in 07/05/2020 10:07:06 4 * @description: Test to parse wsdl 5 * @modified By: 6 * @version: 1.0 7 */ 8 public class WSDLParseTest { 9 private String wsdlLocation = "http://192.168.1.18:8001/CHNAppxServices/services/XfaceSellingTransactionWrapper?wsdl"; 10 11 @Test 12 public void wsdlParseTest () throws Exception { 13 List<String> requestList = BatchWsdlParse.wsdlParse(wsdlLocation); 14 for (String request : requestList) { 15 System.out.println(request); 16 } 17 } 18 19 @Test 20 public void batchWsdlParseTest() throws Exception { 21 List<String> wsdlList = new ArrayList<>(); 22 wsdlList.add(wsdlLocation); 23 List<String> requestList = BatchWsdlParse.batchWsdlParse(wsdlList); 24 for (String request : requestList) { 25 System.out.println(request); 26 } 27 } 28 }
(三)持久化数据库
根据以上代码足以完成对wsdl的批量解析(get和set方法省略),至于将解析后必要的信息持久化数据库,主要是集成了mybatis,若是需要可以参考我的源码,这里就不啰嗦了!
三、个人总结
其实研究过soapui源码的同学肯定知道,其实它也是基于wsdl4j,所以我们完全可以用wsdl4j对wsdl进行解析。之所以研究soapui源码,主要是为了学习学习!