当前位置: 首页 > 编程日记 > 正文

处理器拦截器(HandlerInterceptor)详解

处理器拦截器(HandlerInterceptor)详解

96
编程界的小学生 
2017.04.06 15:19* 字数 881 阅读 657评论 0

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

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

HandlerInterceptor

public interface HandlerInterceptor {/*** 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller* 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;*/boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception;/*** 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。*/void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception;/*** 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中*/void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception;}

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

public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {/*** 默认是true*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return true;}/*** This implementation is empty.*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception {}/*** This implementation is empty.*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {}/*** 不是HandlerInterceptor的接口实现,是AsyncHandlerInterceptor的,AsyncHandlerInterceptor实现了HandlerInterceptor*/@Overridepublic void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {}}

这样在我们业务中比如要记录系统日志,日志肯定是在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方法。若第三个拦截器的preHandle方法return false,则会执行第二个和第一个的postHandle方法和afterCompletion(postHandle都执行完才会执行这个,也就是页面渲染完数据后,执行after进行清理工作)方法。(postHandle和afterCompletion都是倒序执行)

正常流程Demo

package com.bshf.recipe.demo.syslog;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class SyslogInterceptor implements HandlerInterceptor {/*** 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller* 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {System.out.println("==========================================1================================================");return true;}/*** 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {System.out.println("==========================================post1================================================");}/*** 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {System.out.println("==========================================after1================================================");}}
package com.bshf.recipe.demo.syslog;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class SyslogInterceptor2 implements HandlerInterceptor {/*** 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller* 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {System.out.println("==========================================2================================================");return true;}/*** 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {System.out.println("==========================================post2================================================");}/*** 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {System.out.println("==========================================after2================================================");}
}
package com.bshf.recipe.demo.syslog;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class SyslogInterceptor3 implements HandlerInterceptor {/*** 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller* 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {System.out.println("==========================================3================================================");return true;}/*** 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {System.out.println("==========================================post3================================================");}/*** 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {System.out.println("==========================================after3================================================");}
}
<mvc:interceptors><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.bshf.recipe.demo.syslog.SyslogInterceptor" /></mvc:interceptor><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.bshf.recipe.demo.syslog.SyslogInterceptor2" /></mvc:interceptor><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.bshf.recipe.demo.syslog.SyslogInterceptor3" /></mvc:interceptor>
</mvc:interceptors>

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

输出结果:

==========================================1================================================
==========================================2================================================
==========================================3================================================
==========================================post3================================================
==========================================post2================================================
==========================================post1================================================
==========================================after3================================================
==========================================after2================================================
==========================================after1================================================

post和after是倒序的!!!!

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

==========================================1================================================
==========================================2================================================
==========================================3================================================
==========================================after2================================================
==========================================after1================================================

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

来源:http://www.jianshu.com/p/1e8d088c2be9

相关文章:

Datawhale组队学习周报(第018周)

文章目录本周结营的开源内容即将结营的开源内容正在进行的开源内容七月排期的开源内容希望排期的开源内容每周号外Whalepaper 招新公告本周&#xff08;06月14日~06月20日&#xff09;&#xff0c;第 25 期组队学习一共有 3 门开源课程&#xff0c;共组建了 3 个学习群&#xf…

【原创】多台电脑如何公用一个键盘鼠标进行操作 - Mouse with Borders 软件

搞程序开发的同事经常会碰到类似的情况&#xff0c;桌子有多台设备&#xff0c;笔记本&#xff0c;台式机了&#xff0c;经常需要来回切换操作&#xff0c;桌子上摆满了键盘和鼠标&#xff0c;如果要是用同一个键盘或者鼠标&#xff0c;操作这些设备那就很便利了。 给大家推荐一…

Python培训教程分享:如何实现pygame的初始化和退出操作?

本期小编为大家介绍的Python培训教程是关于“如何实现pygame的初始化和退出操作?”的内容&#xff0c;pygame模块针对不同的开发需求提供了不同的子模块&#xff0c;例如显示模块、字体模块、混音器模块等&#xff0c;一些子模块在使用之前必须进行初始化&#xff0c;比如字体…

PLSQL的 dynamic sql小例子

开始 SET serveroutput ON;DECLAREp_tab_name varchar2(20);cursor_name INTEGER;p_rows_del INTEGER; BEGINp_tab_name : EMP_CPY;cursor_name : DBMS_SQL.OPEN_CURSOR;DBMS_SQL.PARSE(cursor_name, DELETE FROM ||p_tab_name, DBMS_SQL.NATIVE);DBMS_OUTPUT.PUT_LINE(p_tab_n…

【青少年编程】陈晓光:打靶游戏

「青少年编程竞赛交流群」已成立&#xff08;适合6至18周岁的青少年&#xff09;&#xff0c;公众号后台回复【Scratch】或【Python】&#xff0c;即可进入。如果加入了之前的社群不需要重复加入。 微信后台回复“资料下载”可获取以往学习的材料&#xff08;视频、代码、文档&…

Phpcms V9手机门户设置教程:怎么用PC V9做手机网站

一、在PHPcms V9管理后台设置手机门户 1.1、开启手机网站。位置&#xff1a;模块 》手机门户 》 添加手机站点&#xff0c;具体设置可参照截图&#xff1a; 填写站点名和LOGO文件相对位置&#xff0c;绑定用于手机网站的二级域名m.cmsyou.com&#xff0c;域名以http://开头。 1…

参加软件测试培训需要学习哪些知识

软件测试在互联网行业的发展前景非常好&#xff0c;很多人都想学习软件测试&#xff0c;其中有很多都是零基础学员&#xff0c;那么参加软件测试培训需要学习哪些知识?零基础是否能学会呢?来看看下面的详细介绍吧。 参加软件测试培训需要学习哪些知识?下面给大家简单说下软件…

C#用XmlDocument操作XML

1.加载xml文件 string xmlPath AppDomain.CurrentDomain.BaseDirectory"xml/test.xml"; XmlDocument xmlDoc new XmlDocument(); xmlDoc.Load(xmlPath);//这里是xml文件的路径 string xmlString"<books><book>test</book></books>…

【第20周复盘】转换思路,让更多的小朋友们参与进来!

「青少年编程竞赛交流群」已成立&#xff08;适合6至18周岁的青少年&#xff09;&#xff0c;公众号后台回复【Scratch】或【Python】&#xff0c;即可进入。如果加入了之前的社群不需要重复加入。 微信后台回复“资料下载”可获取以往学习的材料&#xff08;视频、代码、文档&…

篇三:XPath--解析Html

篇三&#xff1a;XPath--解析Html

Python培训教程:什么是Python全局解释器锁(GIL)?

本期Python培训教程小编为大家带来的是关于“什么是Python全局解释器锁(GIL)?”的问题&#xff0c;全局解释器锁是计算机程序设计语言解释器用于同步线程的工具&#xff0c;使得在同一进程内任何时刻仅有一个线程在执行&#xff0c;常见的有CPython、Ruby MRI。 Python培训教程…

Datawhale组队学习周报(第019周)

本周&#xff08;06月21日~06月27日&#xff09;&#xff0c;第 25 期组队学习一共有 3 门开源课程&#xff0c;共组建了 3 个学习群&#xff0c;参与的学习者有 292 人&#xff0c;其中 web开发入门教程、数据挖掘实战&#xff08;异常检测&#xff09; 已经结营&#xff0c;另…

git ingore添加忽略文件无较的解决方法

一、启动Git Bash并切换到项目目录下 二、执行下列语句&#xff1a; git rm -r --cached . git add . git commit -m update .gitignore 三、OK。

01、WPF 中 URI 解析

WebBrowser 控件导航到包中的 html 文件,首先把该文件 (bland.html) 的属性设置为 "Resource"、“始终复制”&#xff0c; 然后在 C# 页面可以导航到该文件。 webView.Navigate(new Uri(System.Environment.CurrentDirectory "/Assets/bland.html", UriK…

现在参加软件测试培训就业难度大不大?

软件测试对于IT行业来说&#xff0c;入门是相对比较简单的&#xff0c;所以学习起来是非常快的&#xff0c;零基础也可以在短时间内学会&#xff0c;那么现在参加软件测试培训就业难度大不大呢?看出来大家主要关心的是就业问题&#xff0c;来看看下面小编的详细介绍就知道了。…

ABP理论学习之数据传输对象(DTO)

本篇目录 为何需要DTO 领域层抽象数据隐藏序列化和懒加载问题DTO惯例和验证 DTO和实体的自动映射 使用特性和扩展方法进行映射帮助接口DTO用于应用层和 展现层间的数据传输。 展现层调用具有DTO参数的应用服务方法&#xff0c;然后应用服务使用领域对象来执行一些特定的业务逻辑…

Linux如何查看当前目录下文件的个数

查看当前目录下文件的个数 ls -l | grep "^-" | wc -l 查看当前目录下文件的个数&#xff0c;包括子目录里的。 ls -lR| grep "^-" | wc -l 查看某目录下文件夹&#xff08;目录&#xff09;的个数&#xff0c;包括子目录里的。 ls -lR| grep "^d&quo…

迟语寒:组队学习的那些事

很开心又拿到了优秀船员&#xff0c;其实这已不是我第一次参加组队学习了&#xff0c;4月份的二手车是我第一次接触到DataWhale&#xff0c;那次课程结束后&#xff0c;马老师找到我让我分享一下心得&#xff0c;但是我觉得第一次坚持下来不算什么&#xff0c;于是我答应他如果…

Python培训教程分享:Python模块如何导入__all__属性?

本期小编为大家带来的Python培训教程是关于“Python模块如何导入__all__属性?”的内容&#xff0c;后面在工作中是会遇到Python模块这个工作内容的&#xff0c;Python模块的开头通常会定义一个__all__属性&#xff0c;该属性实际上是一个元组&#xff0c;该元组中包含的元素决…

F#探险之旅(三):命令式编程(上)

F#系列随笔索引页面 在本系列的第二部分&#xff08;函数式编程上、中、下&#xff09;中&#xff0c;我们了解了如何使用F#进行纯粹的函数式编程。但是在一些情况下&#xff0c;比如I/O&#xff0c;几乎不能避免改变状态&#xff0c;也就是说会带来side effect。F#并不强求你以…

Spring注解@Component和@resource的使用

http://heavengate.blog.163.com/blog/static/20238105320127234165489/转载于:https://www.cnblogs.com/passer1991/archive/2012/12/05/2802718.html

【青少年编程】黄羽恒:平行空间

「青少年编程竞赛交流群」已成立&#xff08;适合6至18周岁的青少年&#xff09;&#xff0c;公众号后台回复【Scratch】或【Python】&#xff0c;即可进入。如果加入了之前的社群不需要重复加入。 微信后台回复“资料下载”可获取以往学习的材料&#xff08;视频、代码、文档&…

软件测试培训分享:软件测试岗位面试技巧有哪些?

在参加完软件测试培训后&#xff0c;我们最先要准备的就是Python的面试工作了&#xff0c;任何面试都是有技巧的&#xff0c;软件测试也不例外&#xff0c;那么下面小编就为大家详细的介绍一下软件测试岗位面试技巧有哪些?希望可以帮助到大家。 软件测试培训分享&#xff1a;软…

【青少年编程】黄羽恒:Python

「青少年编程竞赛交流群」已成立&#xff08;适合6至18周岁的青少年&#xff09;&#xff0c;公众号后台回复【Scratch】或【Python】&#xff0c;即可进入。如果加入了之前的社群不需要重复加入。 微信后台回复“资料下载”可获取以往学习的材料&#xff08;视频、代码、文档&…

如何把文件隐藏在一张图片里面

该技巧适合 Windows 2000 / XP / Vista 1&#xff1a;准备一张图片&#xff0c;比如 jian.jpg。准备目标文件&#xff0c;比如dan.txt。我们要实现把dan.txt隐藏在图片里面。 2&#xff1a;打开命令行提示符&#xff1a;点击“开始→运行”&#xff0c;输入“cmd”。 3&#xf…

企业级nosql数据库应用与实战-redis

企业级nosql数据库应用与实战-redis项目场景&#xff1a;随着互联网2.0时代的发展&#xff0c;越来越多的公司更加注重用户体验和互动&#xff0c;这些公司的平台上会出现越来越多方便用户操作和选择的新功能&#xff0c;如优惠券发放、抢红包、购物车、热点新闻、购物排行榜等…

如何评判软件测试培训机构的好坏?

想要学习软件测试技术&#xff0c;那么找一家软件测试培训机构无疑是最好的选择&#xff0c;那么如今市面上的软件测试培训机构比较多&#xff0c;如何评判软件测试培训机构的好坏呢?来看看下面的详细介绍。 如何评判软件测试培训机构的好坏?现在国内的软件行业的市场日益增大…

Oracle 11g 新特性 -- Transparent Data Encryption (透明数据加密TDE) 增强 说明

一.TransparentData Encryption (TDE&#xff1a;透明数据加密) 说明Orace TDE 是Orcle 10R2中的一个新特性&#xff0c;其可以用来加密数据文件里的数据&#xff0c;保护从操作系统层面上对数据文件的访问。11g的TDE 在10gR2的基础上增强&#xff0c;允许在表空间级别进行加密…

[USACO07NOV]Cow Relays

mapfloyed矩阵乘法&#xff08;倍增floyed&#xff09; # include <stdio.h> # include <stdlib.h> # include <iostream> # include <algorithm> # include <string.h> # include <map> # define IL inline # define RG register # defin…

NCEPU:线下组队学习周报(011)

线下组队学习 经过一段时间的准备&#xff0c;我们组织的线下组队学习逐步进入正轨。欢迎华北电力大学保定校区的伙伴加入进来大家一起学习一起成长。 我们开展组队学习的内容为&#xff1a; &#xff08;1&#xff09;周志华的《机器学习》&#xff08;西瓜书&#xff09; …