当前位置 博文首页 > blackball1998的博客:添加拦截器

    blackball1998的博客:添加拦截器

    作者:[db:作者] 时间:2021-06-19 19:54

    添加拦截器

    当我们需要在所有的请求处理之前,先做一些预处理,或者在请求处理之后做一些后续处理,或者在处理执行流程中如果有异常则执行一段出错逻辑,这时候我们可以使用Spring MVC的拦截器功能

    事实上这个功能很常用,他的逻辑类似Spring的AOP,在所有的请求处理逻辑之上增加一些增强逻辑

    HandlerInterceptor接口

    首先创建一个拦截器类,并实现HandlerInterceptor接口

    public class MyInterceptor implements HandlerInterceptor {
    }
    

    实现了这个接口之后,我们可以看到可以重写三个方法

    在这里插入图片描述

    这三个方法都有默认实现,我们想要实现什么拦截效果,就重写对应的方法即可,首先介绍preHandle方法

    preHandle方法是在请求处理方法之前执行的,他有一个布尔类型的返回参数,返回true则表示放行该请求,返回false则拦截该请求,我们常使用这个功能来做简单的鉴权功能

    public class MyInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("执行前置处理方法");
            System.out.println(request.getRequestURI());
            return true;
        }
    }
    

    参数列表中的HttpServletRequest 类可以帮助获取到被拦截的请求的请求信息,用于定制拦截逻辑

    当我们返回false值时,拦截器拦截该请求,这个时候浏览器会得到一个空白页面,这个时候可以用参数列表中的HttpServletResponse类来设置页面转发或重定向到登录页面或者初始页面

    注册拦截器

    创建完拦截器之后,我们需要在Spring MVC配置类中添加这个拦截器,这样拦截器才能生效

    重写WebMvcConfigurer接口中的addInterceptors方法来注册拦截器,然后用addPathPatterns方法来绑定需要拦截的请求,如果需要拦截所有的请求,可以使用/**来表示

    @Configuration
    public class MyWebConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
        }
    }
    

    编写一个请求方法来测试拦截结果

    @RestController
    public class MyController {
    
        @RequestMapping("/test")
        public String test() {
            System.out.println("执行请求处理方法");
            return "SUCCESS";
        }
    }
    

    测试结果如下,执行了拦截器中的preHandle方法,也获取到了拦截到的uri

    在这里插入图片描述

    过滤拦截请求

    在绑定拦截的请求时,使用/**来拦截所有请求,但是其中有某些请求我们又不想拦截时,可以使用excludePathPatterns方法来过滤拦截请求,这种情况最常见的场景就是过滤静态资源请求,或者过滤登录页的请求

    假如我有一张静态资源图片,而静态资源请求,一般是不需要拦截的

    在这里插入图片描述

    这时候可以先给静态资源的访问路径先加上一个请求前缀

    spring:
      mvc:
        static-path-pattern: /static/**
    

    这时候访问静态资源需要加上/static这个前缀

    然后在配置拦截器的时候过滤/static/**请求就行了

    @Configuration
    public class MyWebConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/static/**");
        }
    }
    

    拦截器方法的执行流程

    除了preHandle方法,HandlerInterceptor接口还有另外两个方法

    postHandle方法用于在请求方法执行结束后执行一段逻辑,afterCompletion方法用于在视图渲染完成后执行一段逻辑

    public class MyInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("执行preHandle方法");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("执行postHandle方法");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("执行afterCompletion方法");
        }
    }
    

    发送一个测试请求

    在这里插入图片描述

    可以发现他们的执行先后顺序是

    1. 执行preHandle方法
    2. 执行请求处理方法
    3. 执行postHandle方法
    4. 执行afterCompletion方法

    执行出现异常时

    当执行过程出现异常时,无论是preHandle方法,请求处理方法,还是postHandle方法出现了异常,都会触发afterCompletion方法,并且可以通过afterCompletion方法参数列表中的Exception类来获取异常信息

    public class MyInterceptor implements HandlerInterceptor {
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("执行afterCompletion方法");
            System.out.println(ex.getMessage());
        }
    }
    

    我们在请求处理方法中模拟一个异常,测试结果

    @RestController
    public class MyController {
    
        @RequestMapping("/test")
        public String test() {
            System.out.println("执行请求处理方法");
            throw new RuntimeException("模拟异常");
        }
    }
    

    在这里插入图片描述

    可以看到在发生异常时,会触发afterCompletion方法,并且可以获取到异常的信息

    多拦截器执行流程

    当有多个拦截器时,执行顺序如下图

    在这里插入图片描述

    1. 顺序执行所有拦截器的preHandle方法
      • 如果preHandle方法返回true,执行下一个preHandle方法
      • 如果preHandle方法返回false,倒序执行所有已经执行过的拦截器的afterCompletion方法
    2. 如果所有preHandle方法返回true,执行请求处理方法,否则不执行
    3. 如果执行了请求处理方法,倒序执行所有拦截器的postHandle方法
      • 前面的所有步骤,如果有发生异常,则倒序执行所有已经执行过的拦截器的afterCompletion方法
      • 如果无异常,则倒序执行所有拦截器的afterCompletion方法
    下一篇:没有了