Skip to content

SpirngBoot中使用Interceptor拦截器

本篇文章可以带您快速复习拦截器的使用,食用本篇文章前您必须熟练掌握并拥有基于注解配置SpringMVC的能力!

1.快速回顾拦截器

首先我们需要通过以下图片回顾一下SpringMVC中拦截器的执行位置。

image-20220527093757470

  • 拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行

  • 作用:

    1. 在指定的方法调用前后执行预先设定的代码
    2. 阻止原始方法的执行
    3. 总结:拦截器就是用来做增强
  • 拦截器和过滤器之间的区别

    1. 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
    2. 拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强

image-20220527094308906

2.SpringBoot中使用拦截器

  • 创建一个SpringBoot工程并勾选web开发的依赖

    image-20220527094744236

  • 创建完毕后我们需要编写一个UserController类进行测试

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @GetMapping("/login")
        public String login(){
            return "登陆成功!";
        }
    
        @GetMapping("/register")
        public String register(HttpSession session){
            //模拟用户注册,将用户信息存储session域中
            session.setAttribute("user","user");
            return "注册成功!";
        }
    }
    java
  • 然后我们通过浏览器访问这两个路径/login/register

    通过访问可以发现两个接口均可正常访问,但这显然不是我们所期望的,我们期望的是用户在没有注册的情况下直接访问登录接口是失败的,因此我们需要通过添加一个拦截器的功能来实现。

    image-20220527095844136

  • 新建一个拦截器MyInterceptor并实现HandleInterceptor接口

    @Component //将这个类放进spring的容器中
    public class MyInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            HttpSession session = request.getSession();
            //从session域中获取user
            Object user = session.getAttribute("user");
            if (user == null){
                //如果user为null,说明用户没有注册,进行拦截
                response.setStatus(401);
                return false;
            }
            return true;
        }
    }
    java
  • 新建一个SpringMVC的配置类SringMvcConfig用来添加拦截器

    @Configuration
    public class SpringMvcConfig implements WebMvcConfigurer {
    
        @Resource
        private MyInterceptor myInterceptor;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            //添加我们的拦截器,使其生效,addPathPatterns()方法是执行拦截了拦截的路径,默认拦截全部路径
            registry.addInterceptor(myInterceptor).addPathPatterns("/user/login");
        }
    }
    java
  • 此时我们重启项目再次访问两个路径

    image-20220527101812333

3.拦截器的方法说明

我们自定义的拦截器在实现了HandlerInterceptor接口后我们可以选择实现三个方法

3.1 前置处理方法


控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法。

返回false表示拦截,即不调用控制器方法。

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("preHandle()方法被执行!");
    return true;
}
java
  • request:请求对象
  • response:响应对象
  • handler:被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装

使用handler参数,可以获取方法的相关信息

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    HandlerMethod hm = (HandlerMethod)handler;
    String methodName = hm.getMethod().getName();//可以获取方法的名称
    System.out.println("preHandle..."+methodName);
    return true;
}
java

3.2 后置处理方法


原始方法运行后运行,如果原始方法被拦截,则不执行

@Override
public void postHandle(HttpServletRequest req, HttpServletResponse resp, Object handler, ModelAndView mv) throws Exception {
    System.out.println("postHandle()方法被执行!");
}
java
  • 前三个参数和上面的是一致的。

  • modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整

  • 因为咱们现在都是返回json数据,所以该参数的使用率不高。

3.3 完成处理方法


拦截器最后执行的方法,无论原始方法是否执行

@Override
public void afterCompletion(HttpServletRequest req, HttpServletResponse resp, Object handler, Exception ex) throws Exception {
    System.out.println("afterCompletion()方法被执行!");
}
java
  • 前三个参数与上面的是一致的。

  • ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理 ,因为我们现在已经有全局异常处理器类,所以该参数的使用率也不高。

  • 这三个方法中,最常用的是preHandle(),在这个方法中可以通过返回值来决定是否要进行放行,我们可以把业务逻辑放在该方法中,如果满足业务则返回true放行,不满足则返回false拦截。

4.多个拦截器执行顺序

目前,我们在项目中只添加了一个拦截器,如果有多个,该如何配置?配置多个后,执行顺序是什么?

  • 当配置多个拦截器时,形成拦截器链
  • 拦截器链的运行顺序参照拦截器添加顺序为准
  • 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
  • 当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作

image-20220527103811002

preHandle:与配置顺序相同,必定运行

postHandle:与配置顺序相反,可能不运行

afterCompletion:与配置顺序相反,可能不运行。

这个顺序不太好记,最终只需要把握住一个原则即可:以最终的运行结果为准

用心去做高质量的内容网站,欢迎 star ⭐ 让更多人发现