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连在一起 ...
随机推荐
- npm i 出错
npm i npm ERR! code ECONNRESET npm ERR! errno ECONNRESET npm ERR! network request to https://registr ...
- PAT 乙级 1091 N-自守数 (15 分)
1091 N-自守数 (15 分) 如果某个数 K 的平方乘以 N 以后,结果的末尾几位数等于 K,那么就称这个数为“N-自守数”.例如 3×922=25392,而 25392 的末尾两位正好是 ...
- 基于keras的fasttext短文本分类
### train_model.py ### #!/usr/bin/env python # coding=utf-8 import codecs import simplejson as json ...
- [UE4]Named Slot
用户创建的UI成为其他UI的子控件的时候,默认情况下是不能拥有子控件的,给UI添加一个Named Slot,这个UI就可以拥有子控件 一.创建一个名为testNameSlot的UI,添加3个Named ...
- 网络共享存储服务NFS
网络共享存储服务NFS 作者:Eric 微信:loveoracle11g 环境准备 服务器系统 角色 IP RHEL 7.5 x86-64 NFS服务端 192.168.10.201 RHEL 7.5 ...
- linux6下源码安装mysql5.6
概述:CentOS 6.4下通过yum安装的MySQL是5.1版的,比较老,所以就想通过源代码安装高版本的5.6.14.正文:一:卸载旧版本使用下面的命令检查是否安装有MySQL Serverrpm ...
- 安装系统,用cmd进行分区
步骤1:在“您想将Windows安装在何处”的界面按住“Shift+F10”,调出命令行窗口,输入diskpart并点击回车 步骤2: 输入list disk点击回车,列出所有磁盘磁盘是从0开始排序的 ...
- 深入理解volatile
volatile知识点 --------------------------------------------------------------------------- 1.volatile关键 ...
- 高校手机签到系统——第一部分Authority权限系统(上)
序:今天开始写一个算是我第一个系列的文章——高校手机签到系统.本系统结合我们学校自身的一些特点编写.这是我的毕业设计项目,写在这里算是给最后论文的时候一些点滴的记录.另外也想通过这个系列的文章找到一份 ...
- Python 多线程、进程
本节内容 操作系统发展史介绍 进程.与线程区别 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者 ...