基于HandlerInterceptor的拦截器使用及实现

基于HandlerInterceptor的拦截器使用及实现

拦截器的作用,顾名思义,就是对请求进行拦截,做一些额外的处理,在Spring5.1.2中想要实现一个拦截器就只有通过实现HandlerInterceptor接口,重写preHandlepostHandleafterCompletion方法来完成,整个过程都相对简洁易懂。

一、实现自己的拦截器

public class MyInterceptor implements HandlerInterceptor {
    private Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.info("preHandle");
        // 返回false会阻止调用链的继续进行
        return true;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.info("postHandle");
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.info("afterCompletion");
    }
}

实现一个自己拦截器只需要两个步骤即可:

  • 新建一个类实现HandlerInterceptor接口;
  • 重写我们需要的方法,如上的三个方法并不是必须的,视自己的业务需求而定。

在实现了自己的拦截器后还不能马上使用,还需要在Spring中注册与配置,我们新建一个配置类,将上面我们实现的拦截器进行注册,此时拦截器就能生效了。

@Configuration
@EnableWebMvc
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor());
    }
}

启动程序后,我们访问任意的一个Controller就会在控制台看到拦截器中打印的信息:

preHandle
postHandle
afterCompletion

PS :本实验是在SpringBoot中进行的,真的感叹太方便了。

二、多拦截器的处理过程

当我们需要多个拦截器的时候,每个拦截器的方法处理顺序如下:

Interceptor1:preHandle > Interceptor2:preHandle > Interceptor2:postHandle > Interceptor1:postHandle > Interceptor2:afterCompletion > Interceptor1:afterCompletion

我们不妨来写个例子实践一下:

public class MyInterceptor implements HandlerInterceptor {
    private Logger logger = LoggerFactory.getLogger(MyInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.info("MyInterceptor:preHandle");
        return true;
    }

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

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.info("MyInterceptor:afterCompletion");
    }
}
public class YourInterceptor implements HandlerInterceptor {
    private Logger logger = LoggerFactory.getLogger(YourInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.info("YourInterceptor:preHandle");
        return true;
    }

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

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.info("YourInterceptor:afterCompletion");
    }
}
@Configuration
@EnableWebMvc
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor());
        registry.addInterceptor(new YourInterceptor());
    }
}

我们在拦截器配置类InterceptorConfig中添加的顺序就是拦截器执行的顺序,在如上的例子中,MyInterceptor排在YourInterceptor前面,其拦截的结果如下:

MyInterceptor:preHandle
YourInterceptor:preHandle
YourInterceptor:postHandle
MyInterceptor:postHandle
YourInterceptor:afterCompletion
MyInterceptor:afterCompletion

为什么会有这样的执行结果呢?其实这和HandlerInterceptor中三个方法的执行时机有关系:

  • preHandle:在Controller处理之前做拦截进行处理,因此越是声明在前的拦截器,其preHandle方法就越先得到执行。

  • postHandle:在Controller处理之后,视图渲染返回之前进行处理,有点像括号嵌套的机制,左括号越是在前,其对应的右括号越是在后。

    (PS:这里的“返回之前”只是针对视图渲染逻辑的处理,如果是Rest的接口,那么调用会在Controller处理之后直接返回,不会等到postHandle处理完之后才返回)

  • afterCompletion:在所有处理完成后用于对资源进行回收进行处理,因此,所有的afterCompletion都会在所有的preHandlepostHandle之后才会执行,且和postHandle一样,按照右括号规则执行。

三、对特定请求地址的拦截

我们可以在拦截器中定义对那些URL需要拦截,而哪些URL是不需要做任何处理的。

@Configuration
@EnableWebMvc
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 对所有的请求都要拦截,但是“/getInt”不在拦截的范围之内
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**").excludePathPatterns("/getInt");
    }
}

全文完。

你可能感兴趣的:(基于HandlerInterceptor的拦截器使用及实现)