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连在一起 ...
随机推荐
- Reference.svcmap: Could not load file or assembly
Reference.svcmap: Could not load file or assembly 在添加服务的时候出现如上错误, 把这个勾去掉就可以了.
- 如何查看安装python和numpy的版本
命令行下查看python和numpy的版本和安装位置 1.查看python版本 方法一: python -V 注意:‘-V‘中‘V’为大写字母,只有一个‘-’ 方法二: python --versio ...
- Centos6搭建Samba服务并使用Windows挂载
一.安装相关软件 [root@mail ~]# yum install samba samba-client -y #安装相关软件 二.配置匿名访问 [root@mail ~]# cd /etc/sa ...
- React实现了一个鼠标移入的菜单栏效果
<!DOCTYPE html><html> <head> <meta charset="UTF-8" /> <title> ...
- [java,2017-05-16] java中清空StringBuffer的方法以及耗费时间比较
java中清空StringBuffer的方法,我能想到的有4种: 1. buffer.setLength(0); 设置长度为0 2. buffer.delete(0, buffer.length() ...
- django之 使用py文件操作django项目中的表
要想在一个另外的py文件中操作django,可以使用如下的代码 import os os.environ.setdefault("DJANGO_SETTINGS_MODULE",' ...
- 《深入浅出 Java Concurrency》目录
最近在学习J.U.C,看到一个大神 关于这个系列写的非常精辟,由于想做笔记,故系列转载并记录之. 原文:http://www.blogjava.net/xylz/archive/2010/07/08/ ...
- Mac OS X系统 用dd命令将iso镜像写入u盘
一. Mac下将ISO写入U盘可使用命令行工具dd,操作如下: 1.找出U盘挂载的路径,使用如下命令:diskutil list2.将U盘unmount(将N替换为挂载路径):diskutil unm ...
- C程序设计第一次实验报告
C程序设计实验报告 实验项目: 1.字符与ASCII码 2.运算符与表达式的运用 3.顺序结构应用程序 4.数学函数的算法描述 5.鸡兔同笼的算法描述 6.确定坐标的运算描述 姓名:王煜 实验地点:教 ...
- Django之路由系统 Dj
Django之路由系统 Django的路由系统 Django 1.11版本 URLConf官方文档 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调 ...