使用過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源碼,主要是為了學習學習!