拦截器详解

网络上关于Interceptor的文章,但感觉内容都大同小异,而且知识点零零散散,不太方便阅读。因此,整理一篇关于拦截器的文章,在此分享给大家,以供大家参考阅读。

1.概念

  java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前进行拦截,然后再之前或者之后加入某些操作。

       谈到拦截器,还有一个词大家应该知道——拦截器链(Interceptor Chain,在Struts 2中称为拦截器栈Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

2.拦截器的原理
      大部分时候,拦截器方法都是通过代理的方式来调用的。是基于反射实现的,Struts2的拦截器实现相对简单。当请求到达Struts2的ServletDispatcher时,Struts2会查找配置文件,并根据配置实例化相对的拦截器对象,然后串成一个列表(List),最后一个一个的调用列表中的拦截器。Struts2的拦截器是可插拔的,拦截器是AOP的一个实现。Struts2拦截器栈就是将拦截器按一定的顺序连接成一条链。在访问被拦截的方法或者字段时,Struts2拦截器链中的拦截器就会按照之前定义的顺序进行调用。

3.自定义拦截器的步骤
  1)、创建我们自己的拦截器类并实现 HandlerInterceptor 接口。
  2)、创建一个Java类继承WebMvcConfigurerAdapter,并重写 addInterceptors 方法。
  3)、实例化我们自定义的拦截器,然后将对像手动添加到拦截器链中(在addInterceptors方法中添加)。

4.代码示例

IndexInterceptor.java类代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.example.interceptor;
 
import javax.servlet.http.HttpServletRequest;
 
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.servlet.HandlerInterceptor;
 
import org.springframework.web.servlet.ModelAndView;
 
public class IndexInterceptor implements HandlerInterceptor{
 
  @Override
 
  public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
 
      throws Exception {
 
    System.out.println(">>>IndexInterceptor>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)");
 
  }
 
  @Override
 
  public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
 
      throws Exception {
 
    System.out.println(">>>IndexInterceptor>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)");
 
  }
 
  @Override
 
  public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
 
     System.out.println(">>>IndexInterceptor>>>>>>>在请求处理之前进行调用(Controller方法调用之前)");
 
     // 只有返回true才会继续向下执行,返回false取消当前请求
 
     return true;
 
  }
 
}

IndexInterceptor2.java类代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.example.interceptor;
 
import javax.servlet.http.HttpServletRequest;
 
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.servlet.HandlerInterceptor;
 
import org.springframework.web.servlet.ModelAndView;
 
public class IndexInterceptor2 implements HandlerInterceptor{
 
  @Override
 
  public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
 
      throws Exception {
 
    System.out.println(">>>IndexInterceptor2>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)");
 
  }
 
  @Override
 
  public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
 
      throws Exception {
 
    System.out.println(">>>IndexInterceptor2>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)");
 
  }
 
  @Override
 
  public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
 
     System.out.println(">>>IndexInterceptor2>>>>>>>在请求处理之前进行调用(Controller方法调用之前)");
 
     // 只有返回true才会继续向下执行,返回false取消当前请求
 
     return false;
 
  }
 
}

SimpleWebAppConfigurer.java类代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.example.config;
 
import org.springframework.context.annotation.Configuration;
 
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
 
import com.example.interceptor.IndexInterceptor;
 
import com.example.interceptor.IndexInterceptor2;
 
//只要能被springboot扫描到即可
 
@Configuration
 
public class SimpleWebAppConfigurer extends WebMvcConfigurerAdapter{
 
  @Override
 
  public void addInterceptors(InterceptorRegistry registry) {
 
    // 多个拦截器组成一个拦截器链
 
    // addPathPatterns 用于添加拦截规则
 
    // excludePathPatterns 用户排除拦截
 
    registry.addInterceptor(new IndexInterceptor()).addPathPatterns("/**");
 
    registry.addInterceptor(new IndexInterceptor2()).addPathPatterns("/**");
 
    super.addInterceptors(registry);
 
  }
 
}

5.应用场景

1、日志记录,可以记录请求信息的日志,以便进行信息监控、信息统计等。

2、权限检查:如登陆检测,进入处理器检测是否登陆,如果没有直接返回到登陆页面。

3、性能监控:典型的是慢日志

6.注意点

在一个工程中,可以配置多个拦截器,使用多个拦截器,则要注意的是 :多个拦截器使用的时候,prehandler是顺序执行的,而posthandler和afterhandler是倒序执行的;

所以 :如果统一日志处理器拦截器,需要改拦截器prehandler一定要返回true,且将它放在拦截器配置的第一个位置;

      如果登陆认证拦截器,放在拦截器的配置中的第一个位置(有日志处理的话,放在日志处理下面);

      如果有权限校验拦截器,则放在登陆拦截器之后,因为登陆通过后,才可以进行校验权限;

posted @   江南大才子  阅读(830)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示