SpringMVC学习笔记:拦截器和过滤器
首先说明一下二者的区别:
1. 拦截器基于java的反射机制,而过滤器是基于函数回调
2. 拦截器不依赖于servlet容器,过滤器依赖servlet容器
3. 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用
4. 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次
5. 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器注入一个service,可以调用业务逻辑
过滤器和拦截器之间的关系如下图,Filter包裹Servlet,Servlet包裹Interceptor

过滤器的触发时机是容器后,servlet之前,所以过滤器的 doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) 的入参是ServletRequest,而不是HttpServletRequest,因为过滤器在HttpServlet之前
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("before..."); chain.doFilter(request, response); System.out.println("after...");
}
这个chain.doFilter(request, response) 作用是将请求转发给过滤器链上下一个对象,下一个对象是指filter,如果没有filter那就是你请求的资源
拦截器是被包裹在过滤器之中
@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");
}
preHandle 这个方法是在过滤器的 chain.doFilter( request, response ) 方法的前一步执行,且在调用Controller之前调用,当返回false后,会跳过之后的拦截器,并且不会执行所有的拦截器 postHandle ,并且调用返回true的拦截器的 afterCompletion 方法
postHandle 是调用 Controller 之后被调用,但是在渲染 View 页面之前
afterCompletion 是调用完 Controller 接口,渲染 View 页面最后调用,返回true的拦截器都会调用该拦截器的 afterCompletion 方法,顺序相反。这个方法也是在过滤器返回给前端前一步执行
多个过滤器和拦截器是如何配置的呢,下面结合Spring Boot写个demo,地址是 https://gitee.com/colin220/intercept
首先写一个Controller,内容如下:
@Controller
public class InterceptController { @RequestMapping("/index")
public ResponseEntity<?> index() {
System.out.println("Controller Handler");
return ResponseEntity.ok("index");
}
}
这个Controller比较简单,浏览器访问 http://localhost:8080/index 会返回一个字符串 "index"。
写三个过滤器,需要实现javax.servlet.Filter接口,实现其中的三个方法。这三个过滤器分别命名为 FirstFilter SecondFilter ThirdFilter,以FirstFilter为例,其他的两个类内容和其基本一致,其代码内容如下:
import javax.servlet.*;
import java.io.IOException;
@component
public class FirstFilter implements Filter { @Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("FirstFilter init");
} @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
System.out.println("FirstFilter doFilter pre");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("FirstFilter doFilter aft");
} @Override
public void destroy() {
System.out.println("FirstFilter destroy");
}
}
然后写一个配置类,来配置这三个过滤器,其代码内容如下:
@Configuration
public class FilterConfig {
@Autowired
private FirstFilter firstFilter;
@Autowired
private SecondFilter secondFilter;
@Autowired
private ThirdFilter thirdFilter; @Bean
public FilterRegistrationBean filterRegistrationBeanFirst() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
// 可以采用 spring 的依赖注入 20191117update
filterRegistrationBean.setFilter(firstFilter);
filterRegistrationBean.addUrlPatterns("/index/*");
filterRegistrationBean.setName("FirstFilter");
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
} @Bean
public FilterRegistrationBean filterRegistrationBeanSecond() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new SecondFilter());
filterRegistrationBean.addUrlPatterns("/index/*");
filterRegistrationBean.setName("SecondFilter");
filterRegistrationBean.setOrder(2);
return filterRegistrationBean;
} @Bean
public FilterRegistrationBean filterRegistrationBeanThird() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new ThirdFilter());
filterRegistrationBean.addUrlPatterns("/index/*");
filterRegistrationBean.setName("ThirdFilter");
filterRegistrationBean.setOrder(3);
return filterRegistrationBean;
} }
因为有三个Filter,因此需要三个org.springframework.boot.web.servlet.FilterRegistrationBean,每个FilterRegisterationBean中需要设置属性 filterRegistrationBean.setFilter(new FirstFilter( )) ,并设置这个Filter拦截的url,顺序order等属性。

接下来写三个拦截器,需要实现 org.springframework.web.servlet.HandlerInterceptor 接口,重写其中的三个方法,这三个拦截器分别命名为FirstInterceptor SecondInterceptor ThirdInterceptor,以FirstInterceptor为例,其他两个类内容基本一致,其代码内容如下:
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 FirstInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 在请求处理之前进行调用(Controller方法调用之前)
System.out.println("FirstInterceptor preHandle");
return true;
} @Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后 )
System.out.println("FirstInterceptor postHandle");
} @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
System.out.println("FirstInterceptor afterCompletion");
}
}
然后写一个配置类,来配置这三个拦截器。这个配置类要实现org.springframework.web.servlet.config.annotation.WebMvcConfigurer。因为WebMvcConfigurerAdapter 在Spring5.0已被废弃,所以采用WebMvcConfigurer,其代码内容如下:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private FirstInterceptor firstInterceptor;
@Autowired
private SecondInterceptor secondInterceptor;
@Autowired
private ThirdInterceptor thirdInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 可以将 FirstInterceptor 之类的由 spring 进行管理 不建议采用 new 的方法创建对象 20191117update
registry.addInterceptor(firstInterceptor).addPathPatterns("/index/**");
registry.addInterceptor(secondInterceptor).addPathPatterns("/index/**");
registry.addInterceptor(thirdInterceptor).addPathPatterns("/index/**");
} }
其中InterceptorRegistry内部有个List,这个addInterceptor( )方法是用来存放添加进去的interceptor,按照添加的先后顺序,依次拦截。
这样就完成了多个过滤器和多个拦截器的配置,浏览器访问 http://localhost:8080/index 可以看到控制台打印内容如下:

SpringMVC学习笔记:拦截器和过滤器的更多相关文章
- SpringMVC 学习笔记(拦截器的配置))
在设置SpringMVC的拦截器时,需要在SpringMVC中配置 拦截器对象,拦截器的的对象要 实现 HandlerInterceptor 接口 拦截器类的设置: public class inte ...
- 面试题:struts 拦截器和过滤器
拦截器和过滤器的区别 过滤器是servlet规范中的一部分,任何java web工程都可以使用. 拦截器是struts2框架自己的,只有使用了struts2框架的工程才能用. 过滤器在url-patt ...
- SpringMVC的拦截器和过滤器的区别
一 简介 (1)过滤器: 依赖于servlet容器.在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次.使用过滤器的目的是用来做一些过滤操作,获取我们 ...
- springMVC拦截器和过滤器总结
拦截器: 用来对访问的url进行拦截处理 用处: 权限验证,乱码设置等 spring-mvc.xml文件中的配置: <beans xmlns="http://www.springfra ...
- Spring拦截器和过滤器
什么是拦截器 拦截器(Interceptor): 用于在某个方法被访问之前进行拦截,然后在方法执行之前或之后加入某些操作,其实就是AOP的一种实现策略.它通过动态拦截Action调用的对象,允许开发者 ...
- Spring Boot2(七):拦截器和过滤器
一.前言 过滤器和拦截器两者都具有AOP的切面思想,关于aop切面,可以看上一篇文章.过滤器filter和拦截器interceptor都属于面向切面编程的具体实现. 二.过滤器 过滤器工作原理 从上图 ...
- SpringMVC学习 十三 拦截器栈
拦截器栈:就是有多个拦截器同时拦截相同的控制器(controller)请求,这写拦截器就构成了拦截器栈. 栈的特点是先进后出,在拦截器栈中也是如此,如果先执行了preHandle方法,也就是意味着先进 ...
- 1.5(Spring MVC学习笔记) 拦截器(Interceptor)
一.拦截器 1.1拦截器简介 Spring中的拦截器类似Servlet中的过滤器(Filter),主要用于拦截用户请求, 并进行一定的处理操作(如验证权限.记录日志.设置编码方式等). 1.2拦截器实 ...
- struts2学习笔记--拦截器(Interceptor)和登录权限验证Demo
理解 Interceptor拦截器类似于我们学过的过滤器,是可以在action执行前后执行的代码.是我们做web开发是经常使用的技术,比如权限控制,日志.我们也可以把多个interceptor连在一起 ...
随机推荐
- 对于HTML页面中CSS, JS, HTML的加载与执行过程的简单分析
来自 https://blog.csdn.net/u011088260/article/details/79563315 最近在研究HTML页面中JavaScript的执行顺序问题.在Java ...
- [转][C#]Linq 的扩展方法
public static class LinqEx { public static IEnumerable<TResult> LeftExcludingJoin<TSource, ...
- BottomNavigationView 使用
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.Cons ...
- FileProvider相关 Failed to find configured root that contains
问题: 使用FileProvider构造SD卡中文件uri时异常 java.lang.IllegalArgumentException: Failed to find configured root ...
- 第二章 FFmpeg常用命令
2.1 FFmpeg常见的命令大概分为6个部分 ffmpeg信息查询部分 公共操作参数部分 文件主要操作参数部分 视频操作参数部分 字幕操作参数部分 2.1.1 FFmpeg的封装转换 FFmpeg ...
- eclipse中svn切换用户
如果永久保存svn用户账号及密码,再更换svn用户时需要先删除C:\Users\Administrator\AppData\Roaming下的Subversion文件,然后在刷新eclipse中的sv ...
- android 开发 View _1_ View的子类们 和 视图坐标系图
目录: android 开发 View _2_ View的属性动画ObjectAnimator ,动画效果一览 android 开发 View _3_ View的属性动画ValueAnimator a ...
- win10安装mysql一直卡在最后一步进行不下去
新买的电脑,mysql的win10一直安装不了,一直卡在最后一步.仔细阅读下面文章解决. https://blog.csdn.net/fpga_zy/article/details/80689265
- java——IO流01
移动文件有一种简单方法,不需要复制文件再删除文件. package com.unir.test01; import java.io.File; import java.io.IOException; ...
- 连接mysql报错Access denied for user 'root'@'localhost' (using password: YES)解决办法
1.打开MySQL目录下的my.ini文件,在文件的最后添加一行“skip-grant-tables”(免密码登录),保存并关闭文件,重启MySQL服务. 2.通过命令行进入MySQL的BIN目录,输 ...