使用过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源码,主要是为了学习学习!