文章目录

  • Interceptor 拦截器
    • 拦截器中方法的执行流程
    • 传统项目拦截器的配置
    • Spring Boot2.1.2整合拦截器Interceptor 示例
      • Step1 实现HandlerInterceptor接口编写拦截器
      • Step2 实现WebMvcConfigurer接口注册拦截器
      • Step3 验证
    • 多个拦截器的执行顺序
  • Filter 过滤器
    • Spring Boot中整合过滤器Filter的两种方式
      • 方式一 FilterRegistrationBean注册
        • Step1 实现Filter接口 开发过滤器
        • Step2 在配置类中注册该过滤器
        • Step3 启动项目 测试
      • 方式二 @WebServlet+ @ServletComponentScan注解的方式
        • Step1 @WebFilter注解开发过滤器
        • Step2 启动类增加@ServletComponentScan注解
        • Step3 启动测试
  • 小结

Interceptor 拦截器

所有的拦截器都需要实现 HandIerInterceptor 接口

HandlerInterceptor 源码

public interface HandlerInterceptor {// 处理器执行前方法default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return true;}// 处理器处理后方法default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable ModelAndView modelAndView) throws Exception {}// 处理器完成后方法default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable Exception ex) throws Exception {}}

Interceptor依赖于web框架,我们经常在Spring MVC中用到该配置,在这个场景下Interceptor 就依赖于SpringMVC框架。

Interceptor 基于Java的反射机制,属于AOP的一种运用

优点:

  • 由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用

缺点:

  • 只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。

拦截器中方法的执行流程

  • 请求到达 DispatcherServlet,DispatcherServlet 发送至 Interceptor ,执行 preHandle 方法,该方法会返回一个布尔值。如果为 false ,则结束所有流程:如果为 true , 则执行下一步。
  • 请求达到 Controller,执行处理器逻辑,它包含控制器的功能 。
  • 执行 postHandle 方法。
  • 执行视图解析和视图渲染 。
  • 执行 afterComp letion 方法。

传统项目拦截器的配置

基于Spring MVC的项目 ,我们之前的案例配置拦截器的方式如下:


拦截器的开发还是一样的没有变化,那如何注册和实例化拦截器呢? 上面是通过xml的方式来加载的 ,那基于Spring Boot的呢?


Spring Boot2.1.2整合拦截器Interceptor 示例

pom.xml仅需添加 spring-boot-starter-web即可

     <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>

Step1 实现HandlerInterceptor接口编写拦截器

继承HandlerInterceptorAdapter也可以

package com.artisan.interceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;/*** 实现 Handlerlnterceptor接口,覆盖其对应的方法即完成了拦截器的开发* * @author yangshangwei**/public class MyInterceptor implements HandlerInterceptor {/*** preHandle在执行Controller之前执行 * 返回true:继续执行处理器逻辑,包含Controller的功能 * 返回false:中断请求* * 处理器执行前方法*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {System.out.println("MyInterceptor-处理器执行前方法preHandle,返回true则不拦截后续的处理");return true;}/*** postHandle在请求执行完之后 渲染ModelAndView返回之前执行* * 处理器处理后方法*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);System.out.println("MyInterceptor-处理器处理后方法postHandle");}/*** afterCompletion在整个请求执行完毕后执行,无论是否发生异常都会执行* * 处理器完成后方法*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {HandlerInterceptor.super.afterCompletion(request, response, handler, ex);System.out.println("MyInterceptor-处理器完成后方法afterCompletion");}}

Step2 实现WebMvcConfigurer接口注册拦截器

先说明下几个可以用来注册拦截器的类和接口

  • WebMvcConfigurerAdapter: 2.0以后的版本已失效
  • WebMvcConfigurationSupport: 不需要返回逻辑视图,可以选择继承此类
  • WebMvcConfigurer:返回逻辑视图,可以选择实现此方法,重写addInterceptor方法

我们这里选择使用实现WebMvcConfigurer接口

package com.artisan.conf;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import com.artisan.interceptor.MyInterceptor;/*** 实现 WebMvcConfigurer 接 口, 最后覆盖其addInterceptors方法进行注册拦截器* @author yangshangwei**/// 标注为配置类
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {//  注册拦截器到 Spring MVC 机制, 然后 它会返 回 一个拦截器注册InterceptorRegistration regist =  registry.addInterceptor(new MyInterceptor());// 指定拦截匹配模式,限制拦截器拦截请求regist.addPathPatterns("/artisan/interceptor/*");// 不拦截的路径regist.excludePathPatterns("/artisan/interceptor/exclude/*");}}

注意设置的规则,下面测试的时候需要对应上


Step3 验证

package com.artisan.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/artisan")
public class ArtisanController {@GetMapping("/interceptor/test")public String testInterceptor() {System.out.println("执行处理器逻辑testInterceptor....");return "请观察控制台中拦截器的日志输出";}@GetMapping("/interceptor/exclude/test")public String testExcludeInterceptor() {System.out.println("执行处理器逻辑testExcludeInterceptor....");return "exclude排除,不会被拦截器拦截";}
}

启动Spring Boot工程,访问
http://localhost:8080/artisan/interceptor/test 因为匹配到了拦截的规则,所以会被拦截

日志如下


访问 http://localhost:8080/artisan/interceptor/exclude/test 因为匹配到了exclude的规则,所以不会被拦截。 日志中没有拦截器信息的输出


多个拦截器的执行顺序

实际的开发中,多个拦截器是很正常的一个事儿,那么他们的执行顺序又是怎样的呢?

再新建两个拦截器MyInterceptor2和MyInterceptor3,为了验证下执行顺序,不搞的太复杂,代码和MyInterceptor一样,仅仅方法中的输出为了区分改成了对应的类名,如下所示

这3个拦截器的preHandle方法都返回true的情况下

先注册下拦截器

启动工程,访问 http://localhost:8080/artisan/interceptor/test

日志输出

上述结果是责任链模式的规则,对于处理器前方法采用先注册先执行,而处理器后方法和完成方法则是先注册后执行的规则

如果将第二个拦截器MyInterceptor2 的 preHandle 方法修改返回为 false 呢?
测试下,日志输出如下

可以看出处理器前( preHandle )方法会执行,但是一旦返回 false ,则后续的拦截器、 处理器和所有拦截器的处理器后( postHandle ) 方法都不会被执行 。 完成方法 afterCompletion则不一样,它只会执行返回 true 的拦截器的完成方法,而且顺序是先注册后执行 。


Filter 过滤器

在开发传统的Spring项目时web.xml中配置的编码过滤器不知道你还记不记得?

比如这篇很久前写的这个基于Spring的SSM整合文章SSM-Spring+SpringMVC+MyBatis整合案例从0到1 中为了避免编码不一致增加了编码过滤器配置

既然是配置在web.xml中,那肯定是依赖于servlet容器.

优点:

  • 在实现上Filter是基于函数回调,可以对几乎所有请求进行过滤

缺点:

  • 一个过滤器实例只能在容器初始化时调用一次 . 当容器第一次加载该过滤器时,init() 方法将被调用

使用场景:

  • 比如设置编码、过滤敏感词汇、禁止浏览器缓存所有动态页面、实现用户自动登陆、实现URL级别的权限认证等等 ,具体案例参考Filter(过滤器)常见应用

传统的JavaEE项目开发filter的主要2个步骤

  • 实现Filter接口,并实现其doFilter方法。
  • 在 web.xml 文件中使用<filter><filter-mapping>元素对编写的filter类进行注册,并设置它所能拦截的资源
  • 可以开发编写多个Filter,组成一个Filter链,根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter

Spring Boot中整合过滤器Filter的两种方式

方式一 FilterRegistrationBean注册

Step1 实现Filter接口 开发过滤器

package com.artisan.filter;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class HttpFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("HttpFilter  init");Filter.super.init(filterConfig);}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {System.out.println("HttpFilter  doFilter begin");HttpServletRequest req =(HttpServletRequest) request;HttpServletResponse res =(HttpServletResponse) response;System.out.println("HttpFilter name:" + request.getParameter("name"));// 将请求转发给过滤器链上下一个对象。这里的下一个指的是下一个filter,如果没有filter那就是请求的资源。chain.doFilter(request, response);System.out.println("HttpFilter  doFilter end");}@Overridepublic void destroy() {System.out.println("HttpFilter  destroy");Filter.super.destroy();}
}

Step2 在配置类中注册该过滤器

package com.artisan.conf;import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import com.artisan.filter.HttpFilter;@Configuration
public class FilterConfig {@Beanpublic FilterRegistrationBean<HttpFilter> httpFilter(){FilterRegistrationBean<HttpFilter> filterRegistrationBean = new FilterRegistrationBean<HttpFilter>();// 设置filterfilterRegistrationBean.setFilter(new HttpFilter());// 拦截规则filterRegistrationBean.addUrlPatterns("/*");return filterRegistrationBean;}}

Step3 启动项目 测试

观察启动日志

然后访问 http://localhost:8080/artisan/interceptor/test?name=artisan


方式二 @WebServlet+ @ServletComponentScan注解的方式

Step1 @WebFilter注解开发过滤器

@WebFilter 用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器

package com.artisan.filter;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@WebFilter(filterName = "HttpFilter2", urlPatterns = "/*")
public class HttpFilter2 implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("HttpFilter2  init");Filter.super.init(filterConfig);}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {System.out.println("HttpFilter2  doFilter begin");HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse res = (HttpServletResponse) response;System.out.println("HttpFilter2 name:" + request.getParameter("name"));// 将请求转发给过滤器链上下一个对象。这里的下一个指的是下一个filter,如果没有filter那就是请求的资源。chain.doFilter(request, response);System.out.println("HttpFilter2  doFilter end");}@Overridepublic void destroy() {System.out.println("HttpFilter2  destroy");Filter.super.destroy();}
}

Step2 启动类增加@ServletComponentScan注解

在 SpringBootApplication 上使用@ServletComponentScan 注解后,Servlet、Filter、Listener 可以直接通过 @WebServlet、@WebFilter、@WebListener 注解自动注册

Step3 启动测试

观察启动日志

访问 http://localhost:8080/artisan/interceptor/test?name=artisan

注意下filter的执行在interceptor之前


小结

Filter的执行顺序在Interceptor之前 。 拦截器(Interceptor)是基于Java的反射机制,而过滤器(Filter)是基于函数回调。从灵活性上说拦截器功能更强大些,Filter能做的事情,Interceptor都能做,而且可以在请求前,请求后执行,比较灵活。

Spring Boot2.x-12 Spring Boot2.1.2中Filter和Interceptor 的使用相关推荐

  1. Spring Boot2.x-10 基于Spring Boot 2.1.2 + Mybatis 2.0.0实现多数据源,支持事务

    文章目录 概述 思路 步骤 Step1 多数据源配置文件applicaiton.yml Step2 初始化多个数据源 Step3 配置多个数据源 验证测试 支持事务 Step1 配置类中通过@Bean ...

  2. Spring Boot2.x-09 基于Spring Boot 2.1.2 + Mybatis使用自定义注解实现数据库切换

    文章目录 概述 场景说明:读写分离 操作步骤 工程结构 Step1 自定义注解 Step2 数据源定义 Step3 配置文件配置数据源 Step4 数据源实例化DatasourceConfig Ste ...

  3. Spring Boot2 总结(二) Spring Security的基本配置

      Spring Boot对Spring Security提供了自动化配置方案,同时这也是在Spring Boot项目中使用Spring Security的优势,因此Spring Security整合 ...

  4. spring学习12 -Spring 框架模块以及面试常见问题注解等

    以下为spring常见面试问题: 1.Spring 框架中都用到了哪些设计模式? Spring框架中使用到了大量的设计模式,下面列举了比较有代表性的: 代理模式-在AOP和remoting中被用的比较 ...

  5. Spring Security(三十六):12. Spring MVC Test Integration

    Spring Security provides comprehensive integration with Spring MVC Test Spring Security提供与Spring MVC ...

  6. 『互联网架构』软件架构-spring源码之spring结构概述

    spring从07年接触到目前2018年也差不多10年了,一个java的框架为什么能火这么多年.很多人对spring的使用轻车熟路,但是从未解读过spring的源码,老铁跟我一起看看源码,了解下内部的 ...

  7. Spring Boot 应用系列 1 -- Spring Boot 2 整合Spring Data JPA和Druid,双数据源

    最近Team开始尝试使用Spring Boot + Spring Data JPA作为数据层的解决方案,在网上逛了几圈之后发现大家并不待见JPA,理由是(1)MyBatis简单直观够用,(2)以Hib ...

  8. 使用 Spring Boot 快速构建 Spring 框架应用

    https://www.ibm.com/developerworks/cn/java/j-lo-spring-boot/index.html Spring 框架对于很多 Java 开发人员来说都不陌生 ...

  9. 使用 Spring Boot 快速构建 Spring 框架应用--转

    原文地址:https://www.ibm.com/developerworks/cn/java/j-lo-spring-boot/ Spring 框架对于很多 Java 开发人员来说都不陌生.自从 2 ...

最新文章

  1. 如何在JavaScript中获取时间戳
  2. 【原】python中文文本挖掘资料集合
  3. 【转】vscode下编译告警“undefined reference”?三步教你如何解决
  4. 2020年中国无人经济市场研究报告
  5. RecordMyDesktop安装与使用
  6. Error:(1, 1) java: 非法字符: ‘\ufeff’
  7. UVa 12206 (字符串哈希) Stammering Aliens
  8. MCU破解技术分析(一)
  9. idea maven 本地仓库配置报错
  10. 基于轨迹的游客行为特征分析
  11. Windows系统如何mount盘符到目录
  12. 【分享】基于单片机家庭防盗报警系统设计-基于51单片机的智能照明控制系统-基于单片机电压控制灯光亮度报警系统-基于51单片机的公交车安全智能检测系统-基于51单片机的金属探测仪控制设计-毕设课设资料
  13. 15款5号电池横评,小米、南孚电池评测,充电电池评测,小米性价比最高。耐时容量高续航长,充电电池适用高耗电量产品
  14. 【RFID】天线技术
  15. Backtrader量化平台教程(三)Indicator
  16. java DES-CBC加解密
  17. 10_视觉里程计1_三角测量
  18. 5分钟通俗易懂了解什么是云存储
  19. 百胜软件黄飞:携手阿里云,用双中台驱动新零售
  20. 如何在自己网站上播放上传到优酷的视频

热门文章

  1. tf.where 用法
  2. keras实现 vgg16
  3. java json 教程,【简明教程】JSON
  4. php调用接口接口代码无法执行,php调用c接口无错版介绍
  5. MCMC笔记:MCMC的不足
  6. 数据中台实战入门篇:数据中台对内、对外合作机制
  7. MATLAB与图像处理(一):图像中结构张量的求法(Structure Tensor)
  8. 深度学习100例-卷积神经网络(CNN)实现mnist手写数字识别 | 第1天
  9. 知识点讲解四:栈溢出(stack overflow)问题解决方案
  10. LeetCode-动态规划-198. 打家劫舍