首先说明一下二者的区别:

  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学习笔记:拦截器和过滤器的更多相关文章

  1. SpringMVC 学习笔记(拦截器的配置))

    在设置SpringMVC的拦截器时,需要在SpringMVC中配置 拦截器对象,拦截器的的对象要 实现 HandlerInterceptor 接口 拦截器类的设置: public class inte ...

  2. 面试题:struts 拦截器和过滤器

    拦截器和过滤器的区别 过滤器是servlet规范中的一部分,任何java web工程都可以使用. 拦截器是struts2框架自己的,只有使用了struts2框架的工程才能用. 过滤器在url-patt ...

  3. SpringMVC的拦截器和过滤器的区别

    一 简介 (1)过滤器: 依赖于servlet容器.在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次.使用过滤器的目的是用来做一些过滤操作,获取我们 ...

  4. springMVC拦截器和过滤器总结

    拦截器: 用来对访问的url进行拦截处理 用处: 权限验证,乱码设置等 spring-mvc.xml文件中的配置: <beans xmlns="http://www.springfra ...

  5. Spring拦截器和过滤器

    什么是拦截器 拦截器(Interceptor): 用于在某个方法被访问之前进行拦截,然后在方法执行之前或之后加入某些操作,其实就是AOP的一种实现策略.它通过动态拦截Action调用的对象,允许开发者 ...

  6. Spring Boot2(七):拦截器和过滤器

    一.前言 过滤器和拦截器两者都具有AOP的切面思想,关于aop切面,可以看上一篇文章.过滤器filter和拦截器interceptor都属于面向切面编程的具体实现. 二.过滤器 过滤器工作原理 从上图 ...

  7. SpringMVC学习 十三 拦截器栈

    拦截器栈:就是有多个拦截器同时拦截相同的控制器(controller)请求,这写拦截器就构成了拦截器栈. 栈的特点是先进后出,在拦截器栈中也是如此,如果先执行了preHandle方法,也就是意味着先进 ...

  8. 1.5(Spring MVC学习笔记) 拦截器(Interceptor)

    一.拦截器 1.1拦截器简介 Spring中的拦截器类似Servlet中的过滤器(Filter),主要用于拦截用户请求, 并进行一定的处理操作(如验证权限.记录日志.设置编码方式等). 1.2拦截器实 ...

  9. struts2学习笔记--拦截器(Interceptor)和登录权限验证Demo

    理解 Interceptor拦截器类似于我们学过的过滤器,是可以在action执行前后执行的代码.是我们做web开发是经常使用的技术,比如权限控制,日志.我们也可以把多个interceptor连在一起 ...

随机推荐

  1. 解决Ubuntu中文显示为乱码

    1. 安装所需软件 sudo apt-get install zh-autoconvert sudo apt-get install zhcon 2. 配置系统 $ vi /var/lib/local ...

  2. C++Primer第五版——习题答案详解(二)

    习题答案目录:https://www.cnblogs.com/Mered1th/p/10485695.html 第3章 字符串.向量和数组 练习3.2 一次读入一整行 #include<iost ...

  3. Schtasks命令详解(计划任务DOS批处理)

    Schtasks 安排命令和程序定期运行或在指定时间内运行.从计划表中添加和删除任务,按需要启动和停止任务,显示和更改计划任务. 创建新的计划任务. 语法 schtasks/create/tnTask ...

  4. java内存区域之程序计数器

    程序计数器(program counter register) 作用:字节码解释其工作时,通过这个计数器的值的改变,来选取下一条执行的字节码命令. 由于java虚拟机的都线程是通过线程轮流切换,并分配 ...

  5. 导出Excel(Ext 前台部分)

    开发思路: - 序列化当前GridPanel 数据, 表头结构(用于对应关系), 通过控制器Aspose写到Excel中, 然后返回临时文件地址, 弹出窗口下载. function btnExport ...

  6. JavaWeb——JSTL 核心标签库使用

    JSTL 核心标签库标签共有13个,功能上分为4类: 1.表达式控制标签:out.set.remove.catch 2.流程控制标签:if.choose.when.otherwise 3.循环标签:f ...

  7. mysql B+tree

     什么是索引? 索引是为了加速对表中数据行的检索而创建的一种分散存储的数据结构. id和磁盘地址的映射. 关系型数据库存在磁盘当中. 为什要用索引? 索引能极大减少存储引擎需要扫描的数据量. 索引可以 ...

  8. 小程序打开pdf

    wx.downloadFile({ url:"https://xxxxxx.pdf", success(res){ console.log(res) let data = res. ...

  9. Linux下载命令之rpm和yum比较

    RPM和YUM比较 rpm 是linux的一种软件包名称,以.rmp结尾,安装的时候语法为:rpm -ivh,rpm包的安装有一个很大的缺点就是文件的关联性太大,有时候装一个软件要安装很多其他的软件包 ...

  10. python中的异常处理常用方法

    异常处理 什么是异常? 异常就是与正常情况不同,程序在执行过程中出现错误,导致无法执行完毕.异常其实就是代码执行过程中出错. 常见的一些异常 AttributeError 试图访问一个对象没有的属性, ...