测试开发【Mock平台】13基础:拦截器服务实现(四) 简单规则匹配逻辑

news2024/11/24 16:52:31

【Mock平台】为系列测试开发教程,从0到1编码带你一步步使用Spring Boot 和 Antd React框架完成搭建一个测试工具平台,希望作为一个实战项目对各位的测试开发学习之路有帮助,关注公众号发送“mock”获取github项目源码地址,大奇一个专注测试技术干货原创与分享的家伙。

接上一篇最外层接口的匹配,我们继续深入开发内层规则的匹配。其中规则的匹配会涉及到较多的判断处理,以及重复重复内容,所以我们先创建个匹配工具类,来进行代码类化开发。

public class QMockRuleUtil {
    // 规则匹配工具类
}

GET参数处理

实战项目为了简化处理,不论是GET参数还是POST BODY,不使用自带如之前讲到的getParameterMap方法,而是自定义一个方法,专门处理URL中请求参数"a=a1&b=b1&c=c1"成为JSON。如下代码处理进行一次&拆分,再进行一次=拆分。在这里值得注意的是对应值可能没有或者有多个等号的,我做了一定的兼容,但在实际应用过程中还可能出现其他特殊值的兼容情况,请想想如果遇到要如何处理?

public static JSONObject getJsonObjcetByQueryUrl(String paramStr){
        //String paramStr = "a=a1&b=b1&c=c1";
        String[] params = paramStr.split("&");
        JSONObject obj = new JSONObject();
        for (int i = 0; i < params.length; i++) {
            String[] param = params[i].split("=");
            if (param.length >= 2) {
                String key = param[0];
                String value = param[1];
                for (int j = 2; j < param.length; j++) {
                    value += "=" + param[j];
                }
                try {
                    obj.put(key,value);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }
        return obj;
    }

QMockInterceptor.java类中preHandle在匹配接口后,如果是GET请求,我们对其URL参数后的串获取并用自定义的处理工具类方法转换成统一的JSON数据。

if ("GET".equals(requestMethod.toUpperCase())){
    try {

        if (request.getParameterMap().size()!=0) {
            // 获取GET请求参数
            String paramsStr = URLDecoder.decode(request.getQueryString(),"utf-8");
            // 通过自定义转换方法转换成通用的json数据
            reqParamsOrBody = QMockRuleUtil.getJsonObjcetByQueryUrl(paramsStr);
        }
        // resResult = QMockRuleUtil.matchFilter(mockApiEntity,mockApiRuleEntities,reqParamsOrBody);
    }
    catch (JSONException e){
        log.error(e.toString());
    }
}

这样先完成了GET参数的处理,注意这里有一行注释,将在最后一个核心公共方法实现后打开。

POST参数处理

GET的请求参数处理相对简单些,而对于POST一般对应的Body参数,当然也会可以同传Params参数。之前就讲过本套案例不做太复杂逻辑处理,如果有需要请在本系完成对应实战操作后,掌握了对应的技术能力后,根据项目需求进行扩展开发,如果真是对于Mock需求过滤有复杂的要求,一般就需要在产品需求交互上定义清楚,然后代码层面分层处理。

// 获取POST方法的中的Body数据
public static String getBodyString(HttpServletRequest request) throws IOException {
    StringBuilder sb = new StringBuilder();
    InputStream inputStream = null;
    BufferedReader reader = null;
    try {
        inputStream = request.getInputStream();
        reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
        String line = "";
        // 逐行读取
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    // 返回JSON字符串
    return sb.toString();
}

getBodyString 工具类方法字符流的处理方法是在一个POST请求的BODY本身就是要求JSON格式的前提下实现的逻辑。在得到这个JSON字符串后直接进行类型转换即可。其他非JSON格式请求很少见,如果需要请进行通过header传类型做响应匹配处理。

else if ("POST".equals(requestMethod.toUpperCase())){
    try {
        String strbody = QMockRuleUtil.getBodyString(request);
        if (!strbody.isEmpty()) {
            reqParamsOrBody = JSON.parseObject(strbody);
        }

        // resResult = QMockRuleUtil.matchFilter(mockApiEntity,mockApiRuleEntities,reqParamsOrBody);
    }
        catch (JSONException e){
        log.error(e.toString());
    }
} 

在最后我们进行获取规则,增加最后else处理,便可完成完整的逻辑匹配接口和规则的逻辑。

if(mockApiEntities.size() == 1) {
    // 取得 Mock api 唯一值
    QMockApiEntity mockApiEntity = mockApiEntities.get(0);

    // 根据 api id 查询规则列表
    List<QMockApiRuleEntity> mockApiRuleEntities = qMockService.selectApiRuleList(mockApiEntity.getId());
    log.info("Mock规则个数:" + mockApiRuleEntities.size());

    // 根据不同的方法做不同的处理,目前只支持常用的GET和POST
    if ("GET".equals(requestMethod.toUpperCase())){
        // GET参数处理部分
        resResult = QMockRuleUtil.matchFilter(mockApiEntity,mockApiRuleEntities,reqParamsOrBody);
    } else if ("POST".equals(requestMethod.toUpperCase())){
       // POST参数处理部分省略
       resResult = QMockRuleUtil.matchFilter(mockApiEntity,mockApiRuleEntities,reqParamsOrBody);
    } else {
        resResult.put("code", 4008);
        resResult.put("msg", "Mock暂未支持的请求方法");
    }

} else if (mockApiEntities.size() > 1) {
    resResult.put("code", 5000);
    resResult.put("data", new JSONObject());
    resResult.put("msg", "MOCK匹配多个URI请检查配置");
}
else {
    resResult.put("code", 5000);
    resResult.put("data", new JSONObject());
    resResult.put("msg", "MOCK未匹配任何URI请先添加把");
}

上述代码中有“根据 api id 查询规则列表” 的查询,这个查库实现参考上一篇和最初几篇套路式自己我先实现,也当做是检验下自我脱稿编程的代码能力的检验了。学习是需要自我实战才能有效果的,多花点时间将学过的东西独立实践,而不是照着练一遍,你将收获更大的进步。当然如果不会也不用担心,我将在下篇给出代码详细。

简单规则匹配

通过上述的GET/POST的参数获取转换最终得到一个reqParamsOrBody,然后还有上一篇中的得到mockApiEntitymockApiEntity 三个对象数据,这样我们就可以对其简单的匹配逻辑处理了,关键的解释放在代码注释里了。

 // Mock Rule 匹配逻辑
public static JSONObject matchFilter(QMockApiEntity mockApiEntity, List<QMockApiRuleEntity> mockApiRuleEntities, JSONObject reqParamsOrBody){

    JSONObject resResult = new JSONObject();

    // 循环规则列表
    for(QMockApiRuleEntity ruleEntity:mockApiRuleEntities){
        // 如果规则没有配置个过滤条件跳过
        if((ruleEntity.getReqFilter().isEmpty() || ruleEntity.getReqFilter() == null ) && reqParamsOrBody == null) {
            resResult = ruleEntity.getResBody();
            break;
        }

        // 如果有请求参数和配置条件都有进行匹配
        if(!ruleEntity.getReqFilter().isEmpty() && reqParamsOrBody != null) {

            // 规则大于请求参数认为不合理,不做此规则判定
            if (ruleEntity.getReqFilter().size() > reqParamsOrBody.size()){
                continue;
            }

            // 非合理条件均不存在进行key value的一一判定,这里同样简化只做一级过滤
            JSONArray filters = ruleEntity.getReqFilter();
            Boolean assertResult = false;
            for(int i=0; i< filters.size(); i++) {
                // 先看是否有匹配key+相等value 
                // 在页面添加规则的时候录入数据的固定格式为 [{"key":"job","value":"test"}]
                String key = filters.getJSONObject(i).getString("key");
                if(reqParamsOrBody.containsKey(key) && reqParamsOrBody.get(key).toString().equals(filters.getJSONObject(i).get("value"))) {
                    assertResult = true;
                } else {
                    assertResult = false;
                }
            }
            // 如果有获取规则返回值
            if( assertResult ) {
                resResult = ruleEntity.getResBody();
                break;
            }
        }
    }
    // 全没有返回默认
    if (resResult.isEmpty()) {
        resResult = mockApiEntity.getResDefault();
    }

    return resResult;
}

我们最终做下联调运行测试:

特别提醒1:不要忘记需要先自己实现“qMockService.selectApiRuleList”,这是运行前提

​特别提醒2:以上代码文章里不是一下写出来的,实际的边那中中是要不断debug出来的。也非常不建议不是一痛写或者拷贝复制后就直接运行,然后报错太多又很抓狂。

  • GET接口规则命中
    get

  • POST接口规则命中
    post

至此,本篇教程实现到这里,在上一篇基础上我们进一步实现了接口规则的匹配。有了这个能力支持,我们就可以针对同一个接口不同数值的请求匹配返回对应的值了。

下一篇我们会给出接口规则的请求表和全过程,下下篇是一个扩展知识点,然后我们回归到页面的交互开发。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1457454.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

力扣算法Algorithm竞赛模板库(codeforces-go):含了算法竞赛中常用的数据结构和算法实现,助力开发者更高效地解决问题

1.算法Algorithm竞赛模板库&#xff08;codeforces-go&#xff09; 算法竞赛模板库&#xff0c;为算法竞赛爱好者提供了一系列精心设计的算法模板。这个库包含了算法竞赛中常用的数据结构和算法实现&#xff0c;助力开发者更高效地解决问题 一个算法模板应当涵盖以下几点&…

【C++】【类和对象】初始化列表

1.形式和必用场景 初始化列表&#xff1a;以一个冒号开始&#xff0c;接着是一个以逗号分隔的数据成员列表&#xff0c;每个"成员变量"后面跟一个放在括号中的初始值或表达式。 #include<iostream> using namespace std; class Date { public:Date(int year,…

蓝牙BLE学习-GATT和ATT

1. GATT GATT-Generic Attribute profle-通用属性配置文件。GATT层是传输真正数据所在的层。包括了一个数据传输和存储架构以及其基本操作。GATT用来规范attribute中的数据内容&#xff0c;并运用group&#xff08;分组&#xff09;的概念对attribute进行分类管理。没有GATT&a…

幻兽帕鲁游戏联机的时候,显示“网络连接超时”怎么解决?

如果你在游戏联机的时候&#xff0c;显示“网络连接超时”&#xff0c;可以检查下&#xff1a; 1、前提是你已经按照教程部署成功 2、检查防火墙有没有忘记设置&#xff0c;协议是UDP&#xff08;只有TCP不行&#xff0c;一定要有UDP&#xff09;&#xff0c;端口是否填了8211&…

Vue Suspense

<Suspense> 是一项实验性功能。它不一定会最终成为稳定功能&#xff0c;并且在稳定之前相关 API 也可能会发生变化。 <Suspense> 是一个内置组件&#xff0c;用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成&a…

cookie封装,使用更方便

cookie封装 当提到"cookie封装"&#xff0c;通常是指在开发中对浏览器cookie的处理进行封装和管理&#xff0c;以简化代码和提高可维护性。在Web开发中&#xff0c;cookie是一种用于存储少量数据的小文件&#xff0c;存储在用户的浏览器中。它们被广泛用于跟踪用户会…

循环结构(含练习题)

当循环次数或范围确定时&#xff0c;多用for循环&#xff0c;反之多用while循环 循环结构一般由四部分组成&#xff1a; 初始化语句&#xff0c;在循环开始最初执行&#xff0c;并且只执行一次条件判断、步进语句、循环体 for & foreach for循环&#xff0c;循环体可以执…

22-k8s中pod的调度-亲和性affinity

一、概述 在k8s当中&#xff0c;“亲和性”分为三种&#xff0c;节点亲和性、pod亲和性、pod反亲和性&#xff1b; 亲和性分类名称解释说明nodeAffinity节点亲和性通过【节点】标签匹配&#xff0c;用于控制pod调度到哪些node节点上&#xff0c;以及不能调度到哪些node节点上&…

MySQL学习记录——십이 事务

文章目录 1、了解事务2、事务提交3、事务隔离级别1、隔离性和隔离级别2、查看、设置隔离级别3、读未提交4、读提交5、可重复读6、串行化7、总结 4、事务一致性5、事务隔离性1、隐藏字段2、undo日志3、模拟MVCC4、Read View 6、读提交RC、可重复读RR的区别 1、了解事务 MySQL内…

【C语言必刷题】3.二分查找

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有…

成功靠运气还是能力?我写了一个运气模拟器,告诉给你答案

前端训练营&#xff1a;1v1私教&#xff0c;终身辅导计划&#xff0c;帮你拿到满意的 offer。 已帮助数百位同学拿到了中大厂 offer。欢迎来撩~~~~~~~~ 视频版可直接访问&#xff1a;https://www.bilibili.com/video/BV1ct421b7Q7/?vd_source391a8dc379e0da60c77490e3221f097a…

oauthlib,一个强大的 Python 身份校验库!

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站零基础入门的AI学习网站~。 目录 ​编辑 前言 什么是 OAuthLib&#xff1f; 安装 OAuthLib OAuthLib 的主要功能 OAuthLib 的用法 实现…

自己动手写编译器:使用 PDA 实现增强和属性语法的解析

在前面章节中我们了解了增强语法和属性语法&#xff0c;特别是看到了这两种语法的结合体&#xff0c;本节我们看看如何使用前面我们说过的自顶向下自动机来实现这两种语法结合体的解析&#xff0c;这里使用的方法也是成熟编译器常用的一种语法解析算法。 首先我们先给出上一节…

区块链金融科技:技术融合与挑战应对【文末送书-16】

文章目录 前言一.区块链与金融科技的融合&#xff1a;革新金融格局的技术之光1.1区块链技术简介1.2 区块链在金融科技中的应用 二.智能合约2.1 去中心化金融&#xff08;DeFi&#xff09;2.2区块链对金融科技的影响2.3数据安全性 三.区块链与金融科技【文末送书-16】3.1 粉丝福…

如何训练Ai把古诗《如梦令》描写的意境画出来?

常记溪亭日暮&#xff0c;沉醉不知归路。兴尽晚回舟&#xff0c;误入藕花深处。争渡&#xff0c;争渡&#xff0c;惊起一滩鸥鹭。 古诗《如梦令》以其优美的语言和丰富的意境给人留下深刻的印象。今天&#xff0c;我们将借助AI的力量&#xff0c;将这首诗的意境转化为视觉画面…

x86使用页表实现虚拟内存原理分析---使用代码分析

分页机制 这一部分在手册第四章 视频讲解可以看这一个课程 在不使用分页机制的时候, 我们看到的是物理内存, 物理内存有多大, 我们就可以使用多大的内存 使用内存分页机制, 我们就可以扩充访问的地址范围, 也可以实现权限的细分, 实际上就是实现虚拟内存, 将地址进行映射, 看到…

希尔排序算法

目录 ShellSort希尔排序 整体思路 图解分析 【1】预排序 单组排序 多组并排 【2】直接插入排序 关于gap取值 总代码实现 时间复杂度 ShellSort希尔排序 希尔排序法又称缩小增量法。 希尔排序法的基本思想是&#xff1a;先选定一个整数&#xff0c;把待排序文件中所有…

产品经理学习-产品运营《流程管理》

如何进行流程管理 信息可视化 甘特图-流程管理思维导图-方案讨论原型图-活动文档 明确责任制 分工明确&#xff0c;关键环境有主负责人通过时间倒推督促管理 沟通技巧 明确共同利益以结果激励做好信息同步 如何进行监控活动效果 监控活动的效果是要监控数据 活动每个环境的…

MySQL学习记录——십일 索引

文章目录 1、了解索引2、聚簇、非聚簇索引3、操作1、主键索引2、唯一键索引3、普通索引4、注意事项 4、全文索引 1、了解索引 MySQL服务器是在内存中的&#xff0c;所有数据库的CURD操作都是在内存中进行&#xff0c;索引也是如此。索引是用来提高性能的&#xff0c;它通过组织…

[嵌入式系统-16]:RT-Thread -2- 主要功能功能组件详解与API函数说明、API参考手册入口

目录 一、RT-Thread主要功能组件 二、内核组件 2.1 概述 2.2 API 三、设备驱动 3.1 概述 3.2 API 四、通信组件 4.1 概述 4.4 API 五、网络组件 5.1 概述 5.2 API 5.3 补充&#xff1a;MQTT协议 六、文件系统 6.1 概述 6.2 API 七、GUI 组件 7.1 概述 7.2 …