当前位置: 首页 > 工具软件 > vm-mock > 使用案例 >

基于MockServer的Http接口动态响应工具testMockserver----0x01 testMockServer代码说明

盛城
2023-12-01


前言

介绍本工具的功能点,代码相关说明围绕下面3个功能展开:

  1. mockserver回调模式使用
  2. Velocity与mockserver整合使用
  3. dom4j解析带命名空间xml报文

源代码地址:https://gitee.com/jsong123/testmockserver


一、使用mockServer回调模式

主方法为 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());


                                }
                            }

                        }
                );

    }

二、Velocity与mockserver整合使用

使用帮助类 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;
        }
    }

三、dom4j解析带命名空间xml报文

需要解析的请求报文如下, 我使用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;
    }
 类似资料: