处理器拦截器(HandlerInterceptor)详解

转自:

https://blog.csdn.net/HNUST_LIZEMING/article/details/88670402

https://www.jianshu.com/p/1e8d088c2be9

https://www.cnblogs.com/lostyears/p/10706774.html

注意:如果在springboot应用中使用HandlerInterceptor,需要配置拦截器注入到spring容器

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
    @Autowired
    private TimeInterceptor timeInterceptor;

    /**
     * 针对异步的拦截器配置,拦截异步请求
     * @param configurer
     */
    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
        super.configureAsyncSupport(configurer);
        //比如如下给异步服务请求添加拦截器
        //configurer.registerCallableInterceptors((CallableProcessingInterceptor) timeInterceptor);
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(timeInterceptor);
    }
}

简介
SpringWebMVC的处理器拦截器,类似于Servlet开发中的过滤器Filter,用于处理器进行预处理和后处理。

应用场景
1、日志记录,可以记录请求信息的日志,以便进行信息监控、信息统计等。
2、权限检查:如登陆检测,进入处理器检测是否登陆,如果没有直接返回到登陆页面。
3、性能监控:典型的是慢日志。

HandlerInterceptor

 
  1. public interface HandlerInterceptor {

  2.  
  3. /**

  4. * 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller

  5. * 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断

  6. (如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;

  7. */

  8. boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

  9. throws Exception;

  10.  
  11. /**

  12. * 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以

  13. 通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。

  14. */

  15. void postHandle(

  16. HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)

  17. throws Exception;

  18.  
  19. /**

  20. * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中

  21. */

  22. void afterCompletion(

  23. HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

  24. throws Exception;

  25.  
  26. }

拦截器适配器HandlerInterceptorAdapter
有时候我们可能只需要实现三个回调方法中的某一个,如果实现HandlerInterceptor接口的话,三个方法必须实现,不管你需不需要,此时spring提供了一个HandlerInterceptorAdapter适配器(种适配器设计模式的实现),允许我们只实现需要的回调方法。

 
  1. public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {

  2.  
  3. /**

  4. * 默认是true

  5. */

  6. @Override

  7. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

  8. throws Exception {

  9.  
  10. return true;

  11. }

  12.  
  13. /**

  14. * This implementation is empty.

  15. */

  16. @Override

  17. public void postHandle(

  18. HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)

  19. throws Exception {

  20. }

  21.  
  22. /**

  23. * This implementation is empty.

  24. */

  25. @Override

  26. public void afterCompletion(

  27. HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

  28. throws Exception {

  29. }

  30.  
  31. /**

  32. * 不是HandlerInterceptor的接口实现,是AsyncHandlerInterceptor的,AsyncHandlerInterceptor实现了HandlerInterceptor

  33. */

  34. @Override

  35. public void afterConcurrentHandlingStarted(

  36. HttpServletRequest request, HttpServletResponse response, Object handler)

  37. throws Exception {

  38. }

  39.  
  40. }

这样在我们业务中比如要记录系统日志,日志肯定是在afterCompletion之后记录的,否则中途失败了,也记录了,那就扯淡了。一定是程序正常跑完后,我们记录下那些对数据库做个增删改的操作日志进数据库。所以我们只需要继承HandlerInterceptorAdapter,并重写afterCompletion一个方法即可,因为preHandle默认是true。

运行流程图

Paste_Image.png

运行流程总结如下:

1、拦截器执行顺序是按照Spring配置文件中定义的顺序而定的。

2、会先按照顺序执行所有拦截器的preHandle方法,一直遇到return false为止,比如第二个preHandle方法是return false,则第三个以及以后所有拦截器都不会执行。若都是return true,则按顺序加载完preHandle方法。

3、然后执行主方法(自己的controller接口),若中间抛出异常,则跟return false效果一致,不会继续执行postHandle,只会倒序执行afterCompletion方法。

4、在主方法执行完业务逻辑(页面还未渲染数据)时,按倒序执行postHandle方法。若第三个拦截器的postHandle方法return false,则会执行第二个和第一个的postHandle方法和afterCompletion(postHandle都执行完才会执行这个,也就是页面渲染完数据后,执行after进行清理工作)方法。(postHandle和afterCompletion都是倒序执行)

正常流程Demo

 
  1. package com.bshf.recipe.demo.syslog;

  2.  
  3.  
  4. import org.springframework.web.servlet.HandlerInterceptor;

  5. import org.springframework.web.servlet.ModelAndView;

  6.  
  7. import javax.servlet.http.HttpServletRequest;

  8. import javax.servlet.http.HttpServletResponse;

  9.  
  10. public class SyslogInterceptor implements HandlerInterceptor {

  11.  
  12. /**

  13. * 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller

  14. * 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;

  15. */

  16. @Override

  17. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

  18. throws Exception {

  19. System.out.println("==========================================1================================================");

  20. return true;

  21. }

  22.  
  23. /**

  24. * 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。

  25. */

  26. @Override

  27. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,

  28. ModelAndView modelAndView) throws Exception {

  29. System.out.println("==========================================post1================================================");

  30. }

  31.  
  32. /**

  33. * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中

  34. */

  35. @Override

  36. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

  37. throws Exception {

  38. System.out.println("==========================================after1================================================");

  39. }

  40.  
  41. }

 
  1. package com.bshf.recipe.demo.syslog;

  2.  
  3. import org.springframework.web.servlet.HandlerInterceptor;

  4. import org.springframework.web.servlet.ModelAndView;

  5.  
  6. import javax.servlet.http.HttpServletRequest;

  7. import javax.servlet.http.HttpServletResponse;

  8.  
  9. public class SyslogInterceptor2 implements HandlerInterceptor {

  10.  
  11. /**

  12. * 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller

  13. * 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;

  14. */

  15. @Override

  16. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

  17. throws Exception {

  18. System.out.println("==========================================2================================================");

  19. return true;

  20. }

  21.  
  22.  
  23. /**

  24. * 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。

  25. */

  26. @Override

  27. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,

  28. ModelAndView modelAndView) throws Exception {

  29. System.out.println("==========================================post2================================================");

  30. }

  31.  
  32. /**

  33. * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中

  34. */

  35. @Override

  36. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

  37. throws Exception {

  38. System.out.println("==========================================after2================================================");

  39. }

  40. }

 
  1. package com.bshf.recipe.demo.syslog;

  2.  
  3. import org.springframework.web.servlet.HandlerInterceptor;

  4. import org.springframework.web.servlet.ModelAndView;

  5.  
  6. import javax.servlet.http.HttpServletRequest;

  7. import javax.servlet.http.HttpServletResponse;

  8.  
  9. public class SyslogInterceptor3 implements HandlerInterceptor {

  10.  
  11. /**

  12. * 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller

  13. * 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;

  14. */

  15. @Override

  16. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

  17. throws Exception {

  18. System.out.println("==========================================3================================================");

  19. return true;

  20. }

  21.  
  22.  
  23. /**

  24. * 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。

  25. */

  26. @Override

  27. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,

  28. ModelAndView modelAndView) throws Exception {

  29. System.out.println("==========================================post3================================================");

  30. }

  31.  
  32. /**

  33. * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中

  34. */

  35. @Override

  36. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

  37. throws Exception {

  38. System.out.println("==========================================after3================================================");

  39. }

  40. }

 
  1. <mvc:interceptors>

  2. <mvc:interceptor>

  3. <mvc:mapping path="/**"/>

  4. <bean class="com.bshf.recipe.demo.syslog.SyslogInterceptor" />

  5. </mvc:interceptor>

  6.  
  7. <mvc:interceptor>

  8. <mvc:mapping path="/**"/>

  9. <bean class="com.bshf.recipe.demo.syslog.SyslogInterceptor2" />

  10. </mvc:interceptor>

  11.  
  12. <mvc:interceptor>

  13. <mvc:mapping path="/**"/>

  14. <bean class="com.bshf.recipe.demo.syslog.SyslogInterceptor3" />

  15. </mvc:interceptor>

  16. </mvc:interceptors>

<mvc:mapping path="/**"/>需要拦截的路径,这里匹配所有。这里的配置顺序将是拦截器执行顺序。

输出结果:

 
  1. ==========================================1================================================

  2. ==========================================2================================================

  3. ==========================================3================================================

  4. ==========================================post3================================================

  5. ==========================================post2================================================

  6. ==========================================post1================================================

  7. ==========================================after3================================================

  8. ==========================================after2================================================

  9. ==========================================after1================================================

post和after是倒序的!!!!

中断流程Demo
将SyslogInterceptor3的preHandle方法返回false。其他不变,再看输出结果

 
  1. ==========================================1================================================

  2. ==========================================2================================================

  3. ==========================================3================================================

  4. ==========================================after2================================================

  5. ==========================================after1================================================

发现没有了post,post方法一个都没有输出。不仅如此,你的主程序代码(xxx.controller的一个接口)都不会被执行,所以只要遇到return false,则直接进行after清理工作,post和自己主程序代码都将被略过。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java的拦截器HandlerInterceptor允许你在请求处理之前或之后自定义返回结果。你可以通过实现HandlerInterceptor接口并重写其中的三个方法来实现自定义拦截器: ``` public interface HandlerInterceptor { // 请求处理之前调用 boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; // 请求处理之后调用,但是在视图被渲染之前(Controller方法调用之后) void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; // 在整个请求结束之后调用,也就是在DispatcherServlet渲染了对应的视图之后执行(主要是用于进行资源清理工作) void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception; } ``` 你可以在这些方法中自定义返回结果。例如,你可以在`preHandle`方法中设置响应头,或者在`postHandle`方法中设置响应正文。你也可以在`afterCompletion`方法中执行资源清理操作。 要使用自定义拦截器,你需要将其配置到Spring MVC的DispatcherServlet中。你可以通过实现WebMvcConfigurer接口并重写`addInterceptors`方法来完成此操作。 ``` @Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/login"); } } ``` 在上面的例子中,我们将

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值