前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Mock10-拦截器服务实现(一)探索HandlerInterceptor

Mock10-拦截器服务实现(一)探索HandlerInterceptor

作者头像
MegaQi
发布2023-10-21 19:44:24
1840
发布2023-10-21 19:44:24
举报

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

HandlerInterceptor

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

  • preHandle:在 Controller 执行之前调用,如果返回 false,controller 不执行;
  • postHandle:controller 执行之后,且页面渲染之前调用;
  • afterCompletion:页面渲染之后调用,一般用于资源清理操作。
代码语言:javascript
复制
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 代码:

代码语言:javascript
复制
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;
    }
}

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

代码语言:javascript
复制
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 新增加以下依赖包:

代码语言:javascript
复制
<!--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配置另外一个服务端口,比如:

代码语言:javascript
复制
server.port=8089

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

  • GET 请求
代码语言:javascript
复制
> 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模式下启动会晤,并在打上断点。
代码语言:javascript
复制
String query = URLDecoder.decode(request.getQueryString());  // 断点处
Map<String, String[]> param = request.getParameterMap();
  1. 通过postman请求接口并在params和form-data里给定键值对 Img

3. 执行调试模式查看获取的参数值

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

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

前文导读

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-08-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 非典型性程序员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • HandlerInterceptor
相关产品与服务
项目管理
CODING 项目管理(CODING Project Management,CODING-PM)工具包含迭代管理、需求管理、任务管理、缺陷管理、文件/wiki 等功能,适用于研发团队进行项目管理或敏捷开发实践。结合敏捷研发理念,帮助您对产品进行迭代规划,让每个迭代中的需求、任务、缺陷无障碍沟通流转, 让项目开发过程风险可控,达到可持续性快速迭代。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档