详解Spring 拦截器流程及多个拦截器的执行顺序

拦截器是 Spring MVC 中的组件,它可以在进入请求方法前做一些操作,也可以在请求方法后和渲染视图后做一些事情。

拦截器的定义

SpringMVC 的拦截器只需要实现 HandlerInterceptor 接口,并进行配置即可。HandlerInterceptor 接口的定义如下:

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 {
    }
}

在 HandlerInterceptor 中共有三个方法,每个方法的含义如下:

preHandler:进入请求方法之前执行;

postHandler:请求方法执行完成之后执行;

afterCompletion:视图渲染后执行。

拦截器的执行流程

在 preHandle 方法中,它的返回值是 boolean 类型的,它的返回值影响着请求方法,以及 postHandle 和 afterCompletion 的执行。具体如下。

也就是说,在 preHandle 中如果返回 false,那么后续的流程将不被执行,这可能也是拦截器命名的由来。

测试拦截器

写一个简单拦截器,代码如下:

@Slf4j
public class TestInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandler");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandler");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion");
    }
}

创建了一个 TestInterceptor 的监听器类,它实现了 HandlerInterceptor 的所有接口。写完 TestInterceptor 还需要进行注册。代码如下:

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(testInterceptor());
    }

再来写一个简单的请求方法,代码如下:

@GetMapping("test")
public String test()
{
    return "test";
}

来启动我们的项目,并进行访问,控制台的输出如下:

2021-05-05 16:02:08.110  INFO 88509 --- [nio-8081-exec-6] com.example.demo.TestInterceptor         : preHandler
2021-05-05 16:02:08.111  INFO 88509 --- [nio-8081-exec-6] com.example.demo.TestInterceptor         : postHandler
2021-05-05 16:02:08.111  INFO 88509 --- [nio-8081-exec-6] com.example.demo.TestInterceptor         : afterCompletion

多个拦截器的执行顺序

我们来写多个相同的监听器,分别是 TestInterceptor、TestInterceptor2 和 TestInterceptor3。然后我们进行注册,注册代码如下:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(testInterceptor());
    registry.addInterceptor(testInterceptor2());
    registry.addInterceptor(testInterceptor3());
}

请求我们的方法,输出如下:

2021-05-05 16:09:57.735  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : preHandler
2021-05-05 16:09:57.736  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : preHandler2
2021-05-05 16:09:57.736  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor3        : preHandler3
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor3        : postHandler3
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : postHandler2
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : postHandler
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor3        : afterCompletion3
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : afterCompletion2
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : afterCompletion

注意观察输出的顺序,preHandle 方法是按注册顺序进行执行的,而 postHandle 和 afterCompletion 跟注册顺序是相反的。

让 preHandle 进行拦截

我们让 TestInterceptor2 的 preHandle 返回值为 false,然后查看一下输出内容。

2021-05-05 16:14:00.997  INFO 88582 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : preHandler
2021-05-05 16:14:00.998  INFO 88582 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : preHandler2
2021-05-05 16:14:00.998  INFO 88582 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : afterCompletion

可以看到,TestInterceptor2 的 preHandle 的返回值为 false 以后,相当于在 TestInterceptor2 的 preHandle 后续流程则不再继续执行了。

我们调整一下注册的顺序,代码如下:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(testInterceptor2());
    registry.addInterceptor(testInterceptor());
    registry.addInterceptor(testInterceptor3());
}

修改顺序后的输出如下:

2021-05-05 16:17:23.956  INFO 88589 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : preHandler2

可以看到它后面的流程都被拦截了,没有机会执行了。

总结

拦截器是使用一个 List 进行保存,我们可以在项目中添加多个拦截器来完成不同的功能,比如可以进行 Token 的验证,权限的获取等。我们可以放到不同的拦截器中来进行相关的操作。

以上就是详解Spring 拦截器流程及多个拦截器的执行顺序的详细内容,更多关于Spring 拦截器的资料请关注我们其它相关文章!

(0)

相关推荐

  • SpringBoot 拦截器和自定义注解判断请求是否合法

    应用场景举例: 当不同身份的用户请求一个接口时,用来校验用户某些身份,这样可以对单个字段数据进行精确权限控制,具体看代码注释 自定义注解 /** * 对比请求的用户身份是否符合 * @author liuyalong * @date 2020/9/25 16:03 */ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface CompareUser { /** * The name

  • Springmvc异常处理器及拦截器实现代码

    一.异常处理器 1.实现HandlerExceptionResolver接口 package com.wuxi.exceptions; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servl

  • 在spring中手写全局异常拦截器

    为什么要重复造轮子 你可能会问,Spring已经自带了全局异常拦截,为什么还要重复造轮子呢? 这是个好问题,我觉得有以下几个原因 装逼 Spring的全局异常拦截只是针对于Spring MVC的接口,对于你的RPC接口就无能为力了 无法定制化 除了写业务代码,我们其实还能干点别的事 我觉得上述理由已经比较充分的解答了为什么要重复造轮子,接下来就来看一下怎么造轮子 造个什么样的轮子? 我觉得全局异常拦截应该有如下特性 使用方便,最好和spring原生的使用方式一致,降低学习成本 能够支持所有接口

  • SpringBoot之HandlerInterceptor拦截器的使用详解

    前言 平常项目开发过程中,会遇到登录拦截,权限校验,参数处理,防重复提交等问题,那拦截器就能帮我们统一处理这些问题. 一.实现方式 1.1 自定义拦截器 自定义拦截器,即拦截器的实现类,一般有两种自定义方式: 定义一个类,实现org.springframework.web.servlet.HandlerInterceptor接口. 定义一个类,继承已实现了HandlerInterceptor接口的类,例如org.springframework.web.servlet.handler.Handle

  • 解决Springboot @WebFilter拦截器未生效问题

    问题描述 @WebFilter(filterName = "ssoFilter",urlPatterns = "/*") 未生效拦截器 解决方法 在springboot启动类上添加 @ServletComponentScan(basePackages = "full.package.path") 路径替换为@WebFilter所在包 补充知识:在spring boot中使用@WebFilter配置filter(包括排除URL) 我就废话不多说了,

  • spring boot拦截器注入不了java bean的原因

    一.如何实现拦截器 在Spring Boot项目中,拦截器经常被用来做登陆验证,日志记录等操作.拦截器是Spring提供的,所以可以将拦截器注成bean,由IOC容器来管理.实现拦截器的方式很简单,主要由以下两个步骤: 自定义拦截器类实现HandlerInterceptor接口 自定义WebMvc配置类实现WebMvcConfigurer接口,添加自定义拦截器类 简要实现代码如下: 自定义拦截器 LoginInterceptor: public class LoginInterceptor im

  • Spring boot如何基于拦截器实现访问权限限制

    遇到一个需求是:要为用户设置不同的菜单.数据访问权限.对于一些特定类型的数据,有的用户可以看有的用户则不可以.一开始没有太多思路,后来一想是不是可以把"特定类型"这个参数通过@PathVariable注解加到路径上,这样就可以通过拦截器拦截后,校验此用户是否可以访问这个路径(类型)下的数据了. 话不多说,以下为具体实践 拦截器配置类 @Configuration public class UserInterceptorConfig { //为了保证IDbnetUserService提前

  • SpringBoot配置拦截器的示例

    在SpringBoot中配置拦截器,主要有下面两个步骤: 1.继承接口 HandlerInterceptor,根据需要重写其中的三个类. 2.在配置类中注入该类. public class MyInterceptor implements HandlerInterceptor { //controller执行之前 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response,

  • SpringMVC 拦截器的使用示例

    简介 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理.开发者可以自己定义一些拦截器来实现特定的功能. 过滤器 servlet规范中的一部分,任何java web工程都可以使用 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截 拦截器 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用 拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不

  • SpringBoot登录用户权限拦截器

    1. 创建自定义拦截器类并实现 HandlerInterceptor 接口 package com.xgf.online_mall.interceptor; import com.xgf.online_mall.system.domain.User; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.servlet.Ha

  • springboot拦截器过滤token,并返回结果及异常处理操作

    1.springboot 拦截器处理过滤token,并且返回结果 import org.apache.commons.lang3.StringUtils; import org.apache.shiro.subject.Subject; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import org.springframework.web.servlet.H

随机推荐