测试开发【Mock平台】10基础:拦截器实现Mock功能(一)探索HandlerInterceptor

news2024/11/28 22:52:11

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

在本系列 Mock 平台开发过程中,接口拦截服务核心是用到了 spring boot 中的 HandlerInterceptor 类,它主要进行所有请求的拦截服务。另外还需要一个 WebMvcConfigurer 对其拦截内容进行 JavaBean 形式的配置。这一篇我们先来认识和简单的应用HandlerInterceptor,看看如何实现不同需求的拦截。

HandlerInterceptor

通过查看类源代码,HandlerInterceptor 接口类只有三个方法,在我们 controller 应用层面分别表示:

  • preHandle:在 Controller 执行之前调用,如果返回 false,controller 不执行;
  • postHandle:controller 执行之后,且页面渲染之前调用;
  • afterCompletion:页面渲染之后调用,一般用于资源清理操作。
public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

因此要实现接口拦截,我们只需要创建一个类,并通过 implements 实现这个接类,相应地在 preHandle 实现业务逻辑即可。注意我们的项目前后端是完全分离的,所以对于 postHandle 页面渲染和 afterCompletion 资源相关的逻辑用不到。

在之前创建项目的时候,我们就已经创建过一个空的 qmock-service-gateway 服务项目,现在通过 IDE 工具打开此 Spring boot 项目,在 src 跟目录下创建一个自定义拦截器类 QMockInterceptor,并实现接口方法 preHandle 做一个默认的结果返回。这里先举例一个简单可运行的 demo 代码:

package cn.daqi.mock.gateway;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;


@Slf4j
public class QMockInterceptor implements HandlerInterceptor{

    // 在Controller执行之前调用,如果返回false,controller不执行
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("====== 执行Mock服务: START ======");

        // 获取基本请求信息
        String requestURI = request.getRequestURI();
        String requestMethod = request.getMethod();
        log.info("拦截URI为".concat(requestURI).concat(",方法为").concat(requestMethod));

        JSONObject resBody = new JSONObject();
        resBody.put("uri", requestURI);
        resBody.put("method", requestMethod);

        JSONObject resResult = new JSONObject();
        resResult.put("code", 200);
        resResult.put("data", resBody);

        // 封装返回数据
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        PrintWriter printWriter = response.getWriter();

        printWriter.write(JSONObject.toJSONString(resResult));
        printWriter.flush();
        printWriter.close();

        log.info("====== 执行Mock服务: END ======");

        // 只做匹配数据返回,所以不需要执行任何controller
        return false;
    }
}

再添加一个配置器,具体它的方法使用将在后边讲解。

package cn.daqi.mock.gateway;

import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.*;

@SpringBootConfiguration
public class QMockAdapter implements WebMvcConfigurer {

    @Bean
    public QMockInterceptor mockInterceptor(){
        return new QMockInterceptor();
    }

    // 正则匹配所有路径请求
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(new QMockInterceptor()).addPathPatterns("/**");
    }
}

最后运行这个 demo,我们只需要 run QMockServiceGatewayApplication.java 类即可。请注意,这是个新项目如有在拷贝复制代码的过程中遇到依赖报错,记得在 pom.xml 新增加以下依赖包:

<!--web服务包,拦截和配置服务依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--JSON对象-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.56</version>
</dependency>

<!--注解类依赖-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

另外为了避免默认端口冲突,我们还需要给这个项目application.properties配置另外一个服务端口,比如:

server.port=8089

结果验证,我们通过 curl 或者 postman 工具,看是否得到返回

  • GET 请求
> curl http://localhost:8089/api/demo/get
{"code":200,"data":{"method":"GET","uri":"/api/demo/get"}}
  • POST 请求
    在这里插入图片描述

从上边的 demo 中我们注意到 preHandle 方法中的有两个参数类 HttpServletRequest 提供请求信息,和 HttpServletResponse 提供返回信息。

因此我们实现 mock 拦截网关服务的逻辑处理就在于此,通过 request 获取请求方法、路径、参数等去数据库匹配,如果有匹配的配置 mock 数据,则按照设定的返回值塞到 response 中返回来完成接口 Mock 服务。

通过查看源码 HttpServletRequestServletRequest类,里边方法很多可自行查看,这里重点认识下几个获取参数的方法:

  • getQueryString 方法返回请求 URL 中的查询字符串部分,即 URL 中位于问号后面的内容。

    例如,对于 URL ‘http://example.com/page?param1=value1&param2=value2’,getQueryString()方法将返回param1=value1&param2=value2。返回的是一个字符串,包含了原始的查询字符串内容

  • getParameterMap 方法用于获取请求参数的映射,返回一个 Map<String, String[]>对象,其中键是参数名,值是参数值的字符串数组。

    例如,对于URL ‘http://example.com/page?param1=value1&param2=value2’,并且请求体中有参数param3=value3,getParameterMap()方法将返回一个Map,其中包含三个键值对:param1 -> [“value1”],param2 -> [“value2”],param3 -> [“value3”]。它会解析请求中的参数,包括查询字符串和请求体中的参数。如果有多个同名参数,它们将作为数组值存储在Map中。

  • getInputStream 方法用于获取请求的输入流。它返回一个InputStream对象,可以用于读取请求的主体数据。

    当HTTP请求是POST或PUT请求,并且请求中包含主体数据时,可以使用getInputStream()方法来获取请求主体的内容。通过读取输入流,您可以获取请求的原始数据并进行处理,例如解析JSON或其他自定义格式的数据。
    另外需要注意的一点是:一旦使用getInputStream()方法读取了输入流中的数据,就无法再使用getParameter()或getParameterMap()等方法来获取请求参数。这是因为这些方法在读取输入流后会失效。

最后基于上边演示代码,增加两行getQueryString和getParameterMap获取参数的代码,通过打断点来看下都是获取params参数的本质区别:

  1. 增加获取参数代码,debug模式下启动会晤,并在打上断点。
String query = URLDecoder.decode(request.getQueryString());  // 断点处
Map<String, String[]> param = request.getParameterMap();
  1. 通过postman请求接口并在params和form-data里给定键值对值
    在这里插入图片描述

  2. 执行调试模式查看获取的参数值
    在这里插入图片描述

至此,我们实现了请求接口相关信息的拦截,后续我们将在此基础上进行规则​判断返回,来真正实现Mock服务。

下一篇我们稍微扩展的讲一下它的搭档 WebMvcConfigurer ,看看它的一些作用,这样能更结合自身项目需求来更友好的配置。

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

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

相关文章

代码行统计工具---cloc(Count Lines of Code)

介绍 官网&#xff1a; https://github.com/AlDanial/cloc cloc&#xff08;Count Lines of Code&#xff09;是一个代码行统计工具&#xff0c;可以统计源码中的空白行、注释行、物理行&#xff0c;支持对多种语言的统计。 安装 windows下安装 例如&#xff0c;下载1.98版…

华为云云耀云服务器L实例评测|使用宝塔面板管理服务器,并搭建个人博客网站

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 公众号&#xff1a;网络豆 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a; 网络豆的主页​​​​​ 目录 前言 介绍&#xff1a; 一.购买使用华为云云耀服务器 …

【Tomcat服务部署及优化】

Tomcat 一、什么是Tomcat?二、Tomcat 核心组件2.1 Tomcat 组件2.3 Container组件的结构2.4 Tomcat 请求过程 三、Tomcat 部署3.1 安装JDK3.2 设置JDK环境变量3.3 安装Tomcat并用supervisor启动解压添加到supervisord服务测试能否通过supervisorctl启动 四、Tomcat的端口和主要…

ES6中新增加的Map和Set数据结构的使用场景

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ Map 数据结构⭐Set 数据结构⭐Map 和 Set 的使用场景⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是…

bboss 流批一体化框架 与 数据采集 ETL

数据采集 ETL 与 流批一体化框架 特性&#xff1a; 高效、稳定、快速、安全 bboss 是一个基于开源协议 Apache License 发布的开源项目&#xff0c;主要由以下三部分构成&#xff1a; Elasticsearch Highlevel Java Restclient &#xff0c; 一个高性能高兼容性的Elasticsea…

Python中的异常处理3-2

在《Python中的异常处理3-1》中提到&#xff0c;用except可以捕获所有的异常。实际上&#xff0c;在程序运行的过程中&#xff0c;出现异常的原因有很多&#xff0c;比如下标超出范围、除数为0、变量未定义等。 1 except语句加上具体的异常类型 可以在except语句之后加上具体…

基于jeecg-boot集成luckysheet记录

1、放在public下面&#xff0c;开始用下面的&#xff0c;会报错&#xff0c;找不到相应的js文件&#xff0c; <!-- luckysheet for bigscreen --><link relstylesheet href./luckysheet/plugins/css/pluginsCss.css /><link relstylesheet href./luckysheet/pl…

echarts根据x轴数据长度判断是否倾斜展示/柱状图上方显示数字

showChart1() { // 通过id初始化let chart1 echarts.init(document.getElementById(this.idName))var option {// 到容器的距离grid: {top: 18,left: 0,right: 4,bottom: 0,},xAxis: [{type: category,data: this.xData,axisLine: {lineStyle: {color: rgba(255, 255, 255, .…

vscode编辑器一些设置项

vscode编辑器一些设置项 1、工具栏放置位置&#xff08;左侧/右侧&#xff09; 1、工具栏放置位置&#xff08;左侧/右侧&#xff09; 如果这个配置为“hidden”&#xff0c;那么就是隐藏了左侧工具栏&#xff0c;需要将其改为“left”或者“right”即可。 那么在哪里设置呢&am…

运动跑步耳机哪个牌子好、值得推荐的运动耳机

作为一位热衷于运动的爱好者&#xff0c;对于运动装备的要求十分严格。家里有很多手环和跑鞋&#xff0c;但在跑步时最喜欢的是听歌。一首好曲子能够改善跑步体验&#xff0c;延缓疲劳感。当然&#xff0c;并非所有的耳机都适合运动使用&#xff0c;选择运动耳机时需要考虑到运…

【PythonGIS】矢量数据投影转换(坐标转换)

之前跟大家分享过面矢量数据投影转换和点矢量数据投影转换&#xff0c;但博主在日常工作的过程中发现之前分享的面矢量数据投影转换有时候会出现错误&#xff0c;或者转换后的效果不好。再一次偶然的过程中发现了新的坐标转换&#xff08;投影转换&#xff09;函数&#xff0c;…

【linux】进程优先级,进程切换

进程 1.进程优先级&#xff08;了解&#xff09;2.进程切换 1.进程优先级&#xff08;了解&#xff09; 1.什么叫做进程优先级&#xff1f; 我们知道权限是能还是不能做的问题&#xff0c;那对应的优先级就是能做&#xff0c;但是是先做还是后做的问题。 2.为什么存在优先级…

vite项目启动use `--host` to expose

Vite 启动项目后&#xff0c;发现只有localhost 端口 服务&#xff0c;没有 IP 端口服务。 运行npm run serve&#xff0c;终端提示Vite启动后提示Network: use ‘–host’ to expose。 在vite.config.js中配置server import {defineConfig } from vite import vue from vi…

MySQL学习5:事务、存储引擎

事务 简介 事务是一组数据库操作的执行单元&#xff0c;它要么完全执行&#xff0c;要么完全不执行。事务是确保数据库中的数据一致性和完整性的重要机制之一。 事务具有以下四个特性&#xff08;称为ACID特性&#xff09;&#xff1a; 原子性&#xff08;Atomicity&#xf…

Discourse 能支持多少数量的主题

支持主题的数量和 ID 使用的数据类型有关。 根据我们从 Discourse 上 dump 出来的 SQL&#xff0c;我们看到 Discourse 的官方使用 Integer 作为 ID 的数据类型。 随后&#xff0c;我们查看了 pgsql 的官方文档&#xff0c;integer 是 4 字节的&#xff0c;能够存储的最大值为…

智能合约安全分析,假充值攻击如何突破交易所的防御?

智能合约安全分析&#xff0c;假充值攻击如何突破交易所的防御&#xff1f; 引言 假充值攻击&#xff0c;是指攻击者通过利用交易所在处理充值过程中的漏洞或系统错误&#xff0c;发送伪造的交易信息到交易所钱包地址&#xff0c;这些伪造的交易信息被交易所误认为是真实的充值…

系统架构设计师(第二版)学习笔记----计算机网络

【原文链接】系统架构设计师&#xff08;第二版&#xff09;学习笔记----计算机网络 文章目录 一、计算机网络的基本概念1.1 计算机网络的发展阶段1.2 计算机网络的功能1.3 计算机网络的性能指标1.4 计算机网络的非性能指标 二、通信技术2.1 发信机的信号处理流程2.2 收信机的信…

运维经验记录 在CentOS上挂载Windows共享磁盘

1、需求&#xff1a; 非root用户&#xff08;普通用户&#xff09;能够读写windows共享目录&#xff0c;比如查看文件、创建文件、修改文件、删除文件 # 让普通用户也可以正常读写 uidvalue and gidvalue Set the owner and group of the root of the file system (default: …

再谈内存分配器的优缺点

结论 在频繁申请、释放内存的工作场景&#xff0c;建议需要考虑定制化的内存分配器Allocator 优点 那么用内存分配器有那些好处呢&#xff1f;在近段研究和积累看来&#xff0c;主要有以下几点&#xff1a; 拥有连续内存的访问优势较浅的申请、释放栈访问深度&#xff1b;甚…

攻防世界-WEB-upload1

打开靶机上传文件 必须上传图片&#xff0c;F12审计一下代码 发现校验代码 一句话木马&#xff0c;使用菜刀连接 通过bp修改文件类型 get成功&#xff0c;证明文件已经上传 修改POST请求 得到上传成功的文件&#xff0c;请求文件名 得到flag cyberpeace{5a97279c34e62…