摘要:使用过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。
package com.founder.soapui;
import com.eviware.soapui.impl.wsdl.WsdlOperation;
/**
* @author :Mark Wang
* @date :Created in 07/05/2020 10:07:06
* @description: Encapsulates the necessary information of WsdlOperation
* @modified By:
* @version: 1.0
*/
public class OperationInfo {
private String operationName;
private String requestXml;
private String responseXml;
public OperationInfo(WsdlOperation operation) {
operationName = operation.getName();
requestXml = operation.createRequest( true );
responseXml = operation.createResponse(true);
}
}
package com.founder.soapui;
import com.eviware.soapui.impl.wsdl.WsdlInterface;
import com.eviware.soapui.impl.wsdl.WsdlOperation;
import java.util.ArrayList;
import java.util.List;
/**
* @author :Mark Wang
* @date :Created in 07/05/2020 10:07:06
* @description: Encapsulates the necessary information of WsdlInterface
* @modified By:
* @version: 1.0
*/
public class InterfaceInfo {
private String interfaceName;
private List<OperationInfo> operations;
private String[] address;
public InterfaceInfo(WsdlInterface wsdlInterface) {
this.interfaceName = wsdlInterface.getName();
this.address = wsdlInterface.getEndpoints();
int operationNum = wsdlInterface.getOperationCount();
List<OperationInfo> operations = new ArrayList<OperationInfo>();
for(int i = 0; i < operationNum; i++) {
WsdlOperation operation = ( WsdlOperation )wsdlInterface.getOperationAt( i );
OperationInfo operationInfo = new OperationInfo(operation);
operations.add(operationInfo);
}
this.operations = operations;
}
}
package com.founder.soapui;
import com.eviware.soapui.impl.wsdl.WsdlInterface;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlImporter;
import java.util.ArrayList;
import java.util.List;
/**
* @author :Mark Wang
* @date :Created in 07/05/2020 10:07:06
* @description: Load information according to wsdl location
* @modified By:
* @version: 1.0
*/
public class WsdlInfo {
private String wsdlName;
private List<InterfaceInfo> interfaces;
public WsdlInfo(String path) throws Exception {
WsdlProject project = new WsdlProject();
WsdlInterface[] wsdlInterfaces = WsdlImporter.importWsdl( project, path );
this.wsdlName = path;
if(null != wsdlInterfaces)
{
List<InterfaceInfo> interfaces = new ArrayList<InterfaceInfo>();
for(WsdlInterface wsdlInterface : wsdlInterfaces)
{
InterfaceInfo interfaceInfo = new InterfaceInfo(wsdlInterface);
interfaces.add(interfaceInfo);
}
this.interfaces = interfaces;
}
}
}
package com.founder.soapui;
import java.util.ArrayList;
import java.util.List;
/**
* @author :Mark Wang
* @date :Created in 07/05/2020 10:07:06
* @description: Batch parsing WSDL to generate request message
* @modified By:
* @version: 1.0
*/
public class BatchWsdlParse {
private static List<String> soapRequest = new ArrayList<>();
/**
* Parsing WSDL to get request message
* @param wsdlLocation
* @return
* @throws Exception
*/
public static List<String> wsdlParse (String wsdlLocation) throws Exception {
WsdlInfo wsdlInfo = new WsdlInfo(wsdlLocation);
for (InterfaceInfo interfaceInfo : wsdlInfo.getInterfaces()) {
soapRequest.add(parseInterfaceInfo (interfaceInfo));
}
return soapRequest;
}
/**
* Batch wsdl parse
* @param String
* @return
* @throws Exception
*/
public static List<String> batchWsdlParse (List<String> wsdlList) throws Exception {
for (WsdlUrl wsdlUrl : wsdlList) {
WsdlInfo wsdlInfo = new WsdlInfo(wsdlUrl);
for (InterfaceInfo interfaceInfo : wsdlInfo.getInterfaces()) {
soapRequest.add(parseInterfaceInfo (interfaceInfo));
}
}
return soapRequest;
}
/**
* parse InterfaceInfo
* @param interfaceInfo
* @param serviceId
* @return
*/
public static String parseInterfaceInfo (InterfaceInfo interfaceInfo) {
return interfaceInfo.getOperations().get(0).getRequestXml();
}
}
/**
* @author :Mark Wang
* @date :Created in 07/05/2020 10:07:06
* @description: Test to parse wsdl
* @modified By:
* @version: 1.0
*/
public class WSDLParseTest {
private String wsdlLocation = "http://192.168.1.18:8001/CHNAppxServices/services/XfaceSellingTransactionWrapper?wsdl";
@Test
public void wsdlParseTest () throws Exception {
List<String> requestList = BatchWsdlParse.wsdlParse(wsdlLocation);
for (String request : requestList) {
System.out.println(request);
}
}
@Test
public void batchWsdlParseTest() throws Exception {
List<String> wsdlList = new ArrayList<>();
wsdlList.add(wsdlLocation);
List<String> requestList = BatchWsdlParse.batchWsdlParse(wsdlList);
for (String request : requestList) {
System.out.println(request);
}
}
}
(三) 持久化数据库
根据以上代码足以完成对wsdl的批量解析(get和set方法省略),至于将解析后必要的信息持久化数据库,主要是集成了mybatis,若是需要可以参考我的源码,这里就不啰嗦了!
三、个人总结
其实研究过soapui源码的同学肯定知道,其实它也是基于wsdl4j,所以我们完全可以用wsdl4j对wsdl进行解析。之所以研究soapui源码,主要是为了学习学习!