Spring拦截器和过滤器
什么是拦截器
拦截器(Interceptor): 用于在某个方法被访问之前进行拦截,然后在方法执行之前或之后加入某些操作,其实就是AOP的一种实现策略。它通过动态拦截Action调用的对象,允许开发者定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。
拦截器作用
拦截用户的请求并进行相应的处理,比如:判断用户是否登陆,是否在可购买时间内,记录日志信息等。
Spring中两种实现方式
实现HandlerInterceptor接口
通过实现HandlerInterceptor接口, 一般通过继承HandlerInterceptorAdapter抽象类实现。
DispatcherServlet处理流程:DispatcherServlet处理请求时会构造一个Excecution Chain,即(可能多个)拦截器和真正处理请求的Handler
即Interceptor是链式调用的。
preHandle: 在执行Handler之前进行,即Controller方法调用之前执行,主要进行初始化操作。
postHandle: 在执行Handler之后进行,即Controller 方法调用之后执行,主要对ModelAndView对象进行操作。
afterCompletion: 在整个请求结束之后,即渲染对应的视图之后执行, 主要进行资源清理工作。
注意事项: 每个Interceptor的调用会依据它在xml文件中声明顺序依次执行。
DispatcherServlet中拦截器相关
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null ; boolean multipartRequestParsed = false ; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null ; Exception dispatchException = null ; try { //检查是否是请求multipart,如文件上传 processedRequest = checkMultipart(request); multipartRequestParsed = processedRequest != request; // Determine handler for the current request. //请求到处理器(页面控制器)的映射,通过HanMapping进行映射 mappedHandler = getHandler(processedRequest, false ); if (mappedHandler == null || mappedHandler.getHandler() == null ) { noHandlerFound(processedRequest, response); return ; } // Determine handler adapter for the current request. //处理适配,将处理器包装成相应的适配器 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET" .equals(method); if (isGet || "HEAD" .equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { String requestUri = urlPathHelper.getRequestUri(request); logger.debug( "Last-Modified value for [" + requestUri + "] is: " + lastModified); } if ( new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return ; } } //这里是关键,执行处理器相关的拦截器的预处理 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return ; } try { // Actually invoke the handler. //由适配器执行处理器(调用处理器相应功能处理方法) mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); } finally { if (asyncManager.isConcurrentHandlingStarted()) { return ; } } applyDefaultViewName(request, mv); //执行处理器相关的拦截器的后处理 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } //该方法中会调用triggerAfterCompletion,执行处理器相关的拦截器的完成后处理 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return ; } // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { if (getInterceptors() != null ) { //顺序执行拦截器的preHandle方法,如果返回false,则调用triggerAfterCompletion方法 for ( int i = 0 ; i < getInterceptors().length; i++) { HandlerInterceptor interceptor = getInterceptors()[i]; if (!interceptor.preHandle(request, response, this .handler)) { triggerAfterCompletion(request, response, null ); return false ; } this .interceptorIndex = i; } } return true ; } |
1
2
3
4
5
6
7
8
9
10
|
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception { if (getInterceptors() == null ) { return ; } //逆序执行拦截器的postHandle方法 for ( int i = getInterceptors().length - 1 ; i >= 0 ; i--) { HandlerInterceptor interceptor = getInterceptors()[i]; interceptor.postHandle(request, response, this .handler, mv); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception { if (getInterceptors() == null ) { return ; } //逆序执行拦截器的afterCompletion方法 for ( int i = this .interceptorIndex; i >= 0 ; i--) { HandlerInterceptor interceptor = getInterceptors()[i]; try { interceptor.afterCompletion(request, response, this .handler, ex); } catch (Throwable ex2) { logger.error( "HandlerInterceptor.afterCompletion threw exception" , ex2); } } } |
实现WebRequestInterceptor接口
1
2
3
4
5
6
7
8
9
10
11
|
//与HandlerInterceptor的区别在于无法终止访问请求 public interface WebRequestInterceptor { //返回类行为void,与HandlerInterceptor区别就体现在这里 void preHandle(WebRequest request) throws Exception; void postHandle(WebRequest request, ModelMap model) throws Exception; void afterCompletion(WebRequest request, Exception ex) throws Exception; } |
------------------------------------------------
SpringMVC的拦截器Interceptor和过滤器Filter功能非常相似,使用场景也差不多,看起来难以区分。比如两者都能在代码前后插入执行片段,都可以用来实现一些公共组件的功能复用(权限检查、日志记录等),其实它们并不一样,首先了解一下Interceptor和Filter。
一.Interceptor
Interceptor是Spring拦截器,要实现一个拦截器功能可以继承Spring的HandlerInterceptor接口:
package com.hpx.xiyou.wuKong.aop; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; @Component
public class sanZangInterceptor implements HandlerInterceptor{
static public final Logger logger = LoggerFactory.getLogger(sanZangInterceptor.class); @Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
//System.out.println("interceptortest pre");
logger.info("interceptortest pre");
return true;
} @Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
//System.out.println("interceptortest post");
logger.info("interceptortest post");
} @Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
//System.out.println("interceptortest after");
logger.info("interceptortest after");
}
}
HandlerInterceptor接口有三个需要实现的方法:preHandle(),postHandle()和afterCompletion()。
preHandle方法将在请求处理之前调用,SpringMVC中的Interceptor是链式调用的,每个Interceptor的调用都根据它的声明顺序依次执行,且最先执行其preHandle方法,所以可以在该方法中进行一些前置初始化操作或是预处理。该方法的返回值是布尔类型,如果返回false,表示请求结束,后续的Interceptor和Controller都不会再执行了,如果返回true就执行下一个拦截器的preHandle方法,一直到最后一个拦截器preHandle方法执行完成后调用当前请求的Controller方法。
postHandle方法是在当前请求进行处理之后,也就是Controller方法调用结束之后执行,但是它会在DispatcherServlet进行视图渲染之前被调用,所以可以在这个方法中可以对Controller处理之后的ModelAndView对象进行操作。postHandle方法被调用的方向跟preHandle是相反的,也就是说先声明的Interceptor的postHandle方法反而后执行。
afterCompletion方法需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。该方法会在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行,这个方法的主要作用是用于资源清理工作。
实现一个interceptor拦截器类后,需要在配置中配置使它生效:实现 WebMvcConfigurerAdapter并重写 addInterceptors,同时在这个方法里设置要过滤的URL。
package com.hpx.xiyou.wuKong.Adapter; import com.hpx.xiyou.wuKong.aop.sanZangInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration
public class WebConfigurerAdapter extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new sanZangInterceptor()).addPathPatterns("/wukong/**"); }
}
以上配置生效后,当访问/wukong/**类型url时,控制台输出如下,其中controller为controller方法中的打印信息:
interceptortest pre
controller
interceptortest post
interceptortest after
二.Filter
Filter是Spring过滤器,要定义一个Filter类有以下步骤:
首先定义一个Filter类,继承javax.servlet.Filter类,重写其init、doFilter、destroy方法。init()方法会在Filter初始化后进行调用,在init()方法里面我们可以通过FilterConfig访问到初始化参数( getInitParameter()或getInitParameters() )、ServletContext (getServletContext)和当前Filter部署的名称( getFilterName() )等信息。destroy()方法将在Filter被销毁之前调用。而doFilter()方法则是真正进行过滤处理的方法,在doFilter()方法内部,我们可以过滤请求的request和返回的response,同时我们还可以利用FilterChain把当前的request和response传递给下一个过滤器或Servlet进行处理。
public class FilterTest implements Filter { @Autowired private PointService pointService; @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println( "init yes" ); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println( "filter test" ); filterChain.doFilter(servletRequest, servletResponse); // 传递给下一个Filter进行处理 return ; } @Override public void destroy() { System.out.println( "destroy yes" ); } } |
然后在配置中使该Filter生效:
<filter> <filter-name>filtertest</filter-name> <filter- class >FilterTest</filter- class > </filter> <filter-mapping> <filter-name>filtertest</filter-name> <url-pattern>/point/*</url-pattern> </filter-mapping> |
这样,当我们访问/point/*类型的url,控制台输出如下:
init yes
filter test
controller
三.比较
同时配置过滤器和拦截器然后请求,结果如下:
init yes
filter test
interceptortest pre
controller
interceptortest post
interceptortest after
可以看到filter优先于interceptor被调用。
过滤器和拦截器主要区别如下:
1.二者适用范围不同。Filter是Servlet规范规定的,只能用于Web程序中,而拦截器既可以用于Web程序,也可以用于Application、Swing程序中。
2.规范不同。Filter是在Servlet规范定义的,是Servlet容器支持的,而拦截器是在Spring容器内的,是Spring框架支持的。
3.使用的资源不同。同其他代码块一样,拦截器也是一个Spring的组件,归Spring管理,配置在Spring文件中,因此能使用Spring里的任何资源、对象(各种bean),而Filter不行。
4.深度不同。Filter只在Servlet前后起作用,而拦截器能够深入到方法前后、异常跑出前后等,拦截器的使用有更大的弹性。
Spring拦截器和过滤器的更多相关文章
- 面试题:struts 拦截器和过滤器
拦截器和过滤器的区别 过滤器是servlet规范中的一部分,任何java web工程都可以使用. 拦截器是struts2框架自己的,只有使用了struts2框架的工程才能用. 过滤器在url-patt ...
- Spring Boot2(七):拦截器和过滤器
一.前言 过滤器和拦截器两者都具有AOP的切面思想,关于aop切面,可以看上一篇文章.过滤器filter和拦截器interceptor都属于面向切面编程的具体实现. 二.过滤器 过滤器工作原理 从上图 ...
- Spring boot 拦截器和过滤器
1. 过滤器 Filter介绍 Filter可以认为是Servlet的一种“加强版”,是对Servlet的扩展(既可以对请求进行预处理,又可以对处理结果进行后续处理.使用Filter完整的一般流程是: ...
- springMVC拦截器和过滤器总结
拦截器: 用来对访问的url进行拦截处理 用处: 权限验证,乱码设置等 spring-mvc.xml文件中的配置: <beans xmlns="http://www.springfra ...
- SpringMVC学习笔记:拦截器和过滤器
首先说明一下二者的区别: 1. 拦截器基于java的反射机制,而过滤器是基于函数回调 2. 拦截器不依赖于servlet容器,过滤器依赖servlet容器 3. 拦截器只能对action请求起作用,而 ...
- SpringMVC的拦截器和过滤器的区别
一 简介 (1)过滤器: 依赖于servlet容器.在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次.使用过滤器的目的是用来做一些过滤操作,获取我们 ...
- java 拦截器和过滤器区别(转载)
1.拦截器是基于java的反射机制的,而过滤器是基于函数回调 2.过滤器依赖与servlet容器,而拦截器不依赖与servlet容器 3.拦截器只能对action请求起作用,而过滤器则可以对几乎所有的 ...
- struts2拦截器和过滤器区别
1.拦截器是基于java反射机制的,而过滤器是基于函数回调的.2.过滤器依赖于servlet容器,而拦截器不依赖于servlet容器.3.拦截器只能对Action请求起作用,而过滤器则可以对几乎所有请 ...
- java 中的拦截器和过滤器
区别: 1.拦截器是基于java的反射机制的,而过滤器是基于函数回调 2.过滤器依赖与servlet容器,而拦截器不依赖与servlet容器 3.拦截器只能对action请求起作用,而过滤器则可以对几 ...
随机推荐
- python装饰器中@wraps作用--修复被装饰后的函数名等属性的改变
Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的de ...
- Hadoop生态圈-zookeeper的API用法详解
Hadoop生态圈-zookeeper的API用法详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.测试前准备 1>.开启集群 [yinzhengjie@s101 ~] ...
- angularJs实现下拉框多选
话不多说,直接上干货. 肯定需要下拉选插件.必须引入的是 注意 先后顺序 select2.css select2-bootstrap.css select2.min.js angular.min. ...
- 关于css中a标签的样式
CSS为一些特殊效果准备了特定的工具,我们称之为“伪类”.其中有几项是我们经常用到的,下面我们就详细介绍一下经常用于定义链接样式的四个伪类,它们分别是: :link :visited :hover : ...
- 官方资料&一些好的博客与技术点
https://technet.microsoft.com/zh-cn/library/hh848794.aspxzh https://msdn.microsoft.com/en-us/power ...
- [原]Android Fragment 入门介绍
Fragment Fragment 产生,优点,用途,使用方法简介 1 Fragmeng简介 自从Android 3.0中引入fragments 的概念,根据词海的翻译可以译为:碎片.片段.其上的是为 ...
- ML—机器学习常用包(持续更新….)
机器学习是计算机科学和统计学的边缘交叉领域,R关于机器学习的包主要包括以下几个方面: 1)神经网络(Neural Networks): nnet.AMORE以及neuralnet,nnet提供了最常见 ...
- 日常训练赛 Problem C – Complete Naebbirac’s sequence
比赛链接https://vjudge.net/contest/256988#status/17111202012/C/0/ 大意:三个操作,使得输入的数中,从1-n,每一个数出现的次数相同. wa代码 ...
- Redis的五大数据类型
1.String(字符串) String是Redis最基本的类型,一个Key对应一个Value. String类型是二进制安全的,意思是Redis的String可以包含任何数据,比如jpg图片或者序列 ...
- 【API】注册表编程基础-RegCreateKeyEx、RegSetValueEx
1.环境: 操作系统:Windows 10 x64 编译器:VS2015 2.关键函数 LONG WINAPI RegCreateKeyEx( _In_ HKEY hKey, _In_ LPCTSTR ...