拦截器

拦截器的原理

  1. 面向切面编程(AOP
    • 定义AOP是一种编程范式,允许开发者将横切关注点(如日志、事务管理、权限验证等)与业务逻辑代码分离,从而提高代码的可维护性和重用性。
    • 应用:拦截器通过AOP的方式,在不改变原有代码逻辑的情况下,为方法调用添加额外的功能。
  2. 责任链模式
    • 定义:责任链模式是一种行为设计模式,将请求沿着处理者链进行传递,直到有一个处理者处理该请求。
    • 应用:拦截器链(Interceptor Chain)就是责任链模式的一个应用实例。在拦截器链中,每个拦截器都负责处理请求的一部分,然后将请求传递给下一个拦截器,直到请求被完全处理。

拦截器的工作流程

  1. 请求到达:客户端发送请求到服务器,请求首先被DispatcherServlet接收。
  2. 查找拦截器:DispatcherServlet根据配置查找对应的拦截器链。
  3. 执行拦截器
    • preHandle方法:在Controller方法执行之前,拦截器链中的每个拦截器都会执行其preHandle方法。如果preHandle方法返回true,则请求继续传递给下一个拦截器或Controller方法;如果返回false,则请求处理中断,DispatcherServlet会根据配置进行相应处理(如返回错误页面)。
    • Controller方法执行:如果所有拦截器的preHandle方法都返回true,则执行Controller方法。
    • postHandle方法:在Controller方法执行完成后、视图渲染之前,拦截器链中的每个拦截器都会执行其postHandle方法。
    • afterCompletion方法:在整个请求处理完成后(包括视图渲染),拦截器链中的每个拦截器都会执行其afterCompletion方法。

拦截器的作用范围

拦截器是一个spring组件,由spring容器管理,并不依赖于Tomcat等容器,可以单独使用,所以可以拦截所有到达controller的请求

示意图如下:

image-20250305210820994

拦截器的使用

1,创建一个新的包(package),包名可以叫做interceptor

image-20250305204749903

2,在包中创建你需要的拦截器类,如我需要的是一个登录用的拦截器,这个类需要实现HandlerInterceptor这个接口

1
public class  xxxInterceptor implements HandlerInterceptor

3,其中有三个方法按照需求重写

  • preHandle() :这个方法将在请求处理之前进行调用。注意:如果该方法的返回值为false ,将视为当前请求结束,不仅自身的拦截器会失效,还会导致其他的拦截器也不再执行。

  • postHandle():只有在 preHandle() 方法返回值为true 时才会执行。会在Controller 中的方法调用之后,DispatcherServlet 返回渲染视图之前被调用。 注意:postHandle() 方法被调用的顺序跟 preHandle() 是相反的,先声明的拦截器 preHandle() 方法先执行,而postHandle()方法反而会后执行。

  • afterCompletion():只有在 preHandle() 方法返回值为true 时才会执行。在整个请求结束之后, DispatcherServlet 渲染了对应的视图之后执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

//1,判断用户是否存在

UserDTO user = UserHolder.getUser();

//1.1 不存在
if(user==null){
response.setStatus(401);
return false;
}

//1.2 存在

return true;
}

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

4,写完方法后,还需要配置才能使用,在config包下,创建MvcConfig配置类,不要忘了配置类要加@Configuration这个注解

image-20250305204749903

5,在配置类中,需要实现WebMvcConfigurer这个接口

1
public class MvcConfig implements WebMvcConfigurer

6,重写addInterceptors方法

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.excludePathPatterns(
"/shop/**",
"/voucher/**",
"/shop-type/**",
"/upload/**",
"/blog/hot",
"/user/code",
"/user/login"
)
.order(1);

利用registry来注册刚刚写好的拦截器,可以注册器多个,excludePathPatterns是不需要拦截的路径,order则是拦截器链的顺序,数字越小越先执行,

7,在拦截器中若要使用redis等其他资源

  • 配置StringRedisTemplate,配置类中使用@Bean当然不要忘了@Configuration

  • ```java
    @Bean

    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        return new StringRedisTemplate(redisConnectionFactory);
    }
    
    1
    2
    3
    4
    5
    6

    - 注入依赖

    - ```java
    @Resource
    private StringRedisTemplate stringRedisTemplate;
  • @Autowired
        private StringRedisTemplate stringRedisTemplate