介绍本工具的功能点,代码相关说明围绕下面3个功能展开:
源代码地址:https://gitee.com/jsong123/testmockserver
主方法为 startSvr
public static void main(String[] args) {
startSvr();
}
private static void startSvr() {
ClientAndServer server = new ClientAndServer(1100);
server.when(
//匹配 127.0.0.1:1100/tppp 地址,进行处理
request().withMethod("POST")
.withPath("/tppp")
)
.respond(
// 回调函数
new ExpectationResponseCallback() {
public HttpResponse handle(HttpRequest request) {
try {
// 解析请求的xml报文
String reqstr = DataHelper.paraXml(request.getBodyAsString(),"//Contr_Num");
// Velocity的映射上下文类
VelocityContext context = new VelocityContext();
context.put("rand21", DataHelper.generateRand21());
context.put("contrNum",reqstr);
return response()
// 模拟返回响应报文状态码 200
.withStatusCode(OK_200.code())
// 模拟返回准备的http报文header头
.withHeaders(
header("Content-Type", "application/soap+xml;charset=UTF-8"),
header("Accept-Encoding", "gzip, deflate"),
header("Connection", "Keep-Alive")
)
// 模拟报文返回, 使用模板 test.vm, 并导入上下文类 .withBody(VelocityHelper.generateXML("test.vm", context));
} catch (Exception e) {
e.printStackTrace();
return response()
// 发生异常就返回 500 错误响应码 .withStatusCode(INTERNAL_SERVER_ERROR_500.code());
}
}
}
);
}
使用帮助类 VelocityHelper,来处理模板引擎, 报文模板类,上下文匹配的context。
public static String generateXML(String vmFile,
VelocityContext ctx) throws Exception {
try {
// 声明模板引擎
VelocityEngine engine = new VelocityEngine();
// 引擎声明模板文件位置 engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
engine.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
// 初始化
engine.init();
// 模板、模板引擎、上下文映射Ctx 匹配
StringWriter writer = new StringWriter();
Template template = engine.getTemplate(vmFile, "UTF-8");
template.merge(ctx,writer);
System.out.println("writer:" + writer.toString());
// 返回组装好的报文
return writer.toString();
} catch (Exception ex) {
throw ex;
}
}
需要解析的请求报文如下, 我使用fiddle来模拟发送报文调试验证
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header xmlns:ser="http://service.esb.jbbis.com.cn/">
<soaHeader>
<reqTime>20210220193834</reqTime>
<appId>app134</appId>
<transId>32800000320210220000000000003790</transId>
<appSign>3aa8de7398eb8d23d2c940ede7dc95b0</appSign>
<hostName>方法</hostName>
<channelId>037</channelId>
<userRank/>
<originalTransId/>
<cacheId/>
<rptContent/>
<dataSign>4c4c3f62903a0db6c667d46f42315545</dataSign>
<serviceCode>LLLLL</serviceCode>
<serviceTarget/>
<fileName/>
<filePath/>
<callbackUri/>
<bzTransId>13001100000320210220000000003790</bzTransId>
<clientTyp>130011</clientTyp>
<chnlCd>0103</chnlCd>
<sceneCd>TRAN_0007</sceneCd>
<srvSysCd>039</srvSysCd>
<requestTime>2021-02-20 19:38:35.048</requestTime>
<reqIP>100.0.0.0</reqIP>
</soaHeader>
</soap:Header>
<soap:Body xmlns:ser="http://service.esb.jbbis.com.cn/"><ser:lend>
<request>
<requestHeader>
<Data_Typ>1</Data_Typ>
<Serv_Typ>1</Serv_Typ>
<Serv_ID>LLLL</Serv_ID>
<Chnl_Num>037</Chnl_Num>
<Termn_Num>06</Termn_Num>
</requestHeader>
<requestBody>
<Contr_Num>999999999999999</Contr_Num>
<Brw_Money_Amt>1000</Brw_Money_Amt>
<Brw_Money_Int_Rate>3.24</Brw_Money_Int_Rate>
<Brw_Money_Usg>06</Brw_Money_Usg>
<Brw_Money_Matr_Dt>2021-05-19</Brw_Money_Matr_Dt>
<Repay_Mod>01</Repay_Mod>
</requestBody>
</request>
</ser:lend></soap:Body></soap:Envelope>
需要解析响应报文的Contr_Num 字段的内容,回填到响应报文的Contr_Num 字段里面
需要的响应报文如下:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header xmlns:ser="http://service.esb.jbbis.com.cn/">
<soaHeader>
<reqTime>20210220193834</reqTime>
<appId>app134</appId>
<transId>32800000320161752724834927146491</transId>
<appSign>3aa8de7398eb8d23d2c940ede7dc95b0</appSign>
<hostName>方法</hostName>
<channelId>037</channelId>
<userRank/>
<originalTransId/>
<cacheId/>
<rptContent/>
<dataSign>4c4c3f62903a0db6c667d46f42315545</dataSign>
<serviceCode>LLLL</serviceCode>
<serviceTarget/>
<serviceAddress>account/accRecord/onlineDistrOutAcct_v1_0_0_bz</serviceAddress>
<fileName/>
<filePath/>
<callbackUri/>
<bzTransId>13001100000161752724834927146491</bzTransId>
<clientTyp>130011</clientTyp>
<chnlCd>0103</chnlCd>
<sceneCd>TRAN_LOAN_0007</sceneCd>
<srvSysCd>039</srvSysCd>
<requestTime>2021-02-20 19:38:35.048</requestTime>
<reqIP>0.0.0.90</reqIP>
</soaHeader>
</soap:Header><soap:Body xmlns:ser="http://service.esb.jbbis.com.cn/"><ser:lend>
<request>
<requestHeader>
<Data_Typ>1</Data_Typ>
<Serv_Typ>1</Serv_Typ>
<Serv_ID>LLLL</Serv_ID>
<Chnl_Num>037</Chnl_Num>
<Termn_Num>06</Termn_Num>
</requestHeader>
<requestBody>
<Contr_Num>999999999999999</Contr_Num>
</requestBody>
</request>
</ser:lend></soap:Body></soap:Envelope>
使用DataHelper 里面的xml解析类来解析到请求报文的Contr_Num字段, 如下代码注释比较详细就不解释了
/**
*
* @param srcStr 源带命名空间的XML文本
* @param xpath xml文本中需要获取信息的xpath路径
* @return 获取的文本信息
* @throws Exception
*/
public static String paraXml(String srcStr, String xpath) throws Exception {
Document doc;
StringBuilder pathBuilder = new StringBuilder();
Map<String,String> hsMap = new HashMap<String,String>();
try {
//logger.debug("需要解析的XML报文:" + srcStr);
String repStr = handleXML(srcStr);
logger.debug("处理替换不可见字符后的XML报文:" + repStr);
//确认命名空间hsmap
doc = DocumentHelper.parseText(repStr);
logger.debug("xpath:" + pathBuilder.toString());
// Xpath 指定路径
DefaultXPath dxpath = new DefaultXPath(xpath);
// 指定命名空间
dxpath.setNamespaceURIs(Collections.singletonMap("ns2", "http://schemas.xmlsoap.org/soap/envelope/"));
Element ele = (Element)dxpath.selectSingleNode(doc);
String eleTxt = ele.getText();
return eleTxt;
} catch (DocumentException e) {
e.printStackTrace();
logger.error("xml解析错误:" + e.getMessage());
logger.error("报文内容----------->\n" + srcStr);
}
return null;
}
/**
*
* @param srcStr
* @return去除的不可见字符
*/
private static String handleXML(String srcStr) {
String repStr = srcStr.replaceAll("[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]", "");
if(null != repStr && !"".equals(repStr)){
logger.debug("repStr:::::::" + repStr);
logger.debug("lastindexof >, index <" + String.valueOf(repStr.lastIndexOf(">"))+ String.valueOf(repStr.indexOf("<")));
if(repStr.indexOf("<") != -1 && repStr.lastIndexOf(">") != -1 &&( repStr.lastIndexOf(">") > repStr.indexOf("<")))
repStr = repStr.substring(repStr.indexOf("<"), repStr.lastIndexOf(">") + 1);
}
return repStr;
}