拦截器

Java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式,动态拦截Action调用的对象(也就是controller层)。

Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。

自定义拦截器

自定义一个拦截器,只需要实现HandlerInterceptor接口即可,该接口包含三个方法:

  • preHandle():该方法会在控制器方法前执行,其返回值表示是否知道如何写一个接口。中断后续操作。当其返回值为 true 时,表示继续向下执行;返回值为 false 时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)。
  • postHandle():该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。
  • afterCompletion():该方法会在整个请求完成,即视图渲染之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。
@Component
public class SessionIntercepter implements HandlerInterceptor { @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 {
// 设置字符编码
response.setCharacterEncoding("UTF-8");
} @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(response.getCharacterEncoding());
}
}

自定义拦截器生效

想要Spring Boot 拦截器生效很简单,只需要定义一个配置类,实现 WebMvcConfigurer 接口,实现其中的 addInterceptors() 方法即可。

@Configuration
public class WebConfig implements WebMvcConfigurer { @Autowired
private SessionIntercepter sessionIntercepter; @Override
public void addInterceptors(InterceptorRegistry registry) {
// 拦截器拦截路径
registry.addInterceptor(sessionIntercepter).addPathPatterns("/**");
}
}

运用例子

  • 开发中可能会经常遇到短时间内由于用户的重复点击导致几秒之内重复的请求,可能就是这几秒之内由于各种问题,比如网络、事务的隔离性等等问题导致了数据的重复等问题,因此在日常开发中必须规避这类重复请求操作,这就可以使用拦截器来实现;
  • 开发中经常遇到用户的权限问题。可以在用户登录的时候将用户信息(包括权限信息)加密后放入jwt token中,在每次请求接口的时候拦截并判断该用户是否具有访问该接口的权限。

过滤器

Filter 也称为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如JSP,servlet,静态图片文件或静态HTML文件进行拦截,从而实现一些特殊功能。例如实现URL级别的权限控制、过滤敏感词汇、压缩响应信息等一些高级功能。

执行原理

当客户端发出Web资源的请求时,Web服务器根据应用程序配置文件设置的过滤规则进行检查,若客户请求满足过滤规则,则对请求/响应进行拦截,对请求头和请求数据进行检查或改动,并依次通过过滤器链,最后把请求/响应交给请求的Web资源处理。请求信息在过滤器链中可以被修改,也可以根据条件让请求不发往资源处理器,并直接向客户端返回一个响应。当资源处理器完成了对资源的处理后,响应信息将逐级逆向返回。同样在这个过程中,用户可以修改响应信息,从而完成一定的任务,如图:



服务器会按照过滤器定义的先后顺序组成一条链,然后一次执行其中的doFilter()方法。执行的顺序如图所示,执行第一个过滤器的chain.doFilter()之前的代码,第二个过滤器的chain.doFilter()之前的代码,请求的资源,第二个过滤器的chain.doFilter()之后的代码,第一个过滤器chain.doFilter()之后的代码,最后返回响应。

自定义 Filter

自定义 Filter,只需要实现 javax.servlet.Filter 接口,重写其中的方法即可。

@Component
public class WeFilter implements Filter { @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 继续执行下一个 filter
filterChain.doFilter(servletRequest, servletResponse);
}
}

配置 Filter

方法一

配置类中使用@Bean注入(推荐使用)

@Configuration
public class FilterConfig { @Autowired
private WeFilter weFilter1; @Autowired
private WeFilter weFilter2; @Bean
public FilterRegistrationBean injectFilterOne() {
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(weFilter1);
registrationBean.addUrlPatterns("/*");
registrationBean.setName("filter_one");
// 优先级
registrationBean.setOrder(1);
return registrationBean;
} @Bean
public FilterRegistrationBean injectFilterTwo() {
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(weFilter2);
registrationBean.addUrlPatterns("/*");
registrationBean.setName("filter_one");
// 优先级
registrationBean.setOrder(2);
return registrationBean;
}
}

注意:设置的优先级别决定了过滤器的执行顺序

方法二

使用@WebFilter,@WebFilter时Servlet3.0的一个注解,用于标注一个Filter,Spring Boot也是支持这种方式的,只需要在自定义的Filter上标注该注解即可。

@WebFilter(filterName = "filter_one", urlPatterns = {"/*"})
public class WeFilter implements Filter { @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 继续执行下一个 filter
filterChain.doFilter(servletRequest, servletResponse);
}
}

要想@WebFilter注解生效,需要在配置类上标注另外一个注解@ServletComponentScan用于扫描使其生效。

@SpringBootApplication
@ServletComponentScan(value = {"com.example.demo.filter"})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

运用例子

对于前后端分离的项目来说跨越是一个难题,对于跨越问题有很多解决方案,比如JSONP,网关支持等。用过滤器也可以解决跨越问题,原理很简单,只需要在请求头中添加相应支持跨越的内容即可。

@Component
public class WeFilter implements Filter { @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
// 继续执行下一个 filter
filterChain.doFilter(servletRequest, servletResponse);
}
}

配置类中注入

@Configuration
public class FilterConfig { @Autowired
private WeFilter weFilter; @Bean
public FilterRegistrationBean injectFilterOne() {
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(weFilter);
registrationBean.addUrlPatterns("/*");
registrationBean.setName("filter_one");
// 优先级
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registrationBean;
}
}

过滤器的内容虽然简单,但是在实际开发中不可或缺,比如常用的权限控制框架Shiro,Spring Security,内部都是使用过滤器,了解一下对以后的深入学习有着固本的作用。

拦截器和过滤器的区别

  1. 拦截器是基于Java的反射机制,而过滤器是基于函数回调;
  2. 拦截器不依赖servlet容器,过滤器依赖servlet容器;
  3. 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用;
  4. 拦截器可以访问action上下文、值栈里的对象,过滤器不能访问;
  5. 在action生命周期中,拦截器可以多次被调用,过滤器只能在容器初始化时被调用一次。

SpringBoot 拦截器 & 过滤器的更多相关文章

  1. SpringBoot拦截器中Bean无法注入(转)

    问题 这两天遇到SpringBoot拦截器中Bean无法注入问题.下面介绍我的思考过程和解决过程: 1.由于其他bean在service,controller层注入一点问题也没有,开始根本没意识到Be ...

  2. 【SpringBoot】SpringBoot拦截器实战和 Servlet3.0自定义Filter、Listener

    =================6.SpringBoot拦截器实战和 Servlet3.0自定义Filter.Listener ============ 1.深入SpringBoot2.x过滤器Fi ...

  3. SpringBoot 拦截器获取http请求参数

    SpringBoot 拦截器获取http请求参数-- 所有骚操作基础 目录 SpringBoot 拦截器获取http请求参数-- 所有骚操作基础 获取http请求参数是一种刚需 定义拦截器获取请求 为 ...

  4. Java结合SpringBoot拦截器实现简单的登录认证模块

    Java结合SpringBoot拦截器实现简单的登录认证模块 之前在做项目时需要实现一个简单的登录认证的功能,就寻思着使用Spring Boot的拦截器来实现,在此记录一下我的整个实现过程,源码见文章 ...

  5. SpringBoot拦截器中无法注入bean的解决方法

    SpringBoot拦截器中无法注入bean的解决方法 在使用springboot的拦截器时,有时候希望在拦截器中注入bean方便使用 但是如果直接注入会发现无法注入而报空指针异常 解决方法: 在注册 ...

  6. Springboot拦截器未起作用

    之前遇到要使用springboot拦截器却始终未生效的状况,查了网上的博客,大抵都是@Component,@Configuration注解未加,或是使用@ComponentScan增加包扫描,但是尝试 ...

  7. SpringBoot拦截器中service或者redis注入为空的问题

    原文:https://my.oschina.net/u/1790105/blog/1490098 这两天遇到SpringBoot拦截器中Bean无法注入问题.下面介绍我的思考过程和解决过程: 1.由于 ...

  8. springboot + 拦截器 + 注解 实现自定义权限验证

    springboot + 拦截器 + 注解 实现自定义权限验证最近用到一种前端模板技术:jtwig,在权限控制上没有用springSecurity.因此用拦截器和注解结合实现了权限控制. 1.1 定义 ...

  9. Springboot 拦截器配置(登录拦截)

    Springboot 拦截器配置(登录拦截) 注意这里环境为springboot为2.1版本 1.编写拦截器实现类,实现接口   HandlerInterceptor, 重写里面需要的三个比较常用的方 ...

  10. Springboot拦截器实现IP黑名单

    Springboot拦截器实现IP黑名单 一·业务场景和需要实现的功能 以redis作为IP存储地址实现. 业务场景:针对秒杀活动或者常规电商业务场景等,防止恶意脚本不停的刷接口. 实现功能:写一个拦 ...

随机推荐

  1. LeeCode 栈与队列问题(二)

    LeeCode 239: 滑动窗口最大值 题目描述 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口内的 k 个数字.滑动窗口每次只向右 ...

  2. LNMP搭建静态网页服务器

    chattr -i default/.user.ini LNMP搭建使用 1.安装screen,命令或者操作可以一直运行下去 yum install screen 2.获取及安装 LNMP wget ...

  3. 使用 Transformers 进行图分类

    在之前的 博文 中,我们探讨了图机器学习的一些理论知识.这一篇我们将探索如何使用 Transformers 库进行图分类.(你也可以从 此处 下载演示 notebook,跟着一起做!) 目前,Tran ...

  4. 景顺长城基于 Apache APISIX 在金融云原生的生产实践

    本文介绍了景顺长城在金融云原生架构演进中选择 APISIX 作为网关工具的技术细节,同时分享了使用 APISIX 的实践细节,并对 APISIX 的未来展望进行了探讨. 作者李奕浩,景顺长城信息技术部 ...

  5. c语言趣味编程(1)百钱百鸡

    一.问题描述 百钱买百鸡问题:公鸡五文钱一只,母鸡三文钱一只,小鸡三只一文钱,用100文钱买100只鸡,公鸡.母鸡.小鸡各买多少只 二.设计思路 (1)定义三个变量下x,y,z代表公鸡,母鸡,小鸡的数 ...

  6. Python用哈希算法查找相似图片(包括不同分辨率,不同大小,不同格式的图片)

    # -*- coding: utf-8 -*- ''' Python用哈希算法查找相似图片并放入[_df]的文件夹中 相似图片包括不同分辨率,不同大小,不同格式,只要图片相似就会算重复文件 安装cv2 ...

  7. 09-devserver

    const {resolve} = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.ex ...

  8. DeFi4-稳定币

    稳定币--稳定 是一个相对的度量指标 波动性,收益率标准差 在一个时间段内最大跌幅 Fiat,例如: 欧元.英镑的波动率为6-12% (波动本身并不能反映价格的范围 稳定币 vs 锚定币 稳定币类型 ...

  9. [Pytorch框架] 4.5 多GPU并行训练

    文章目录 4.5 多GPU并行训练 4.5.1 torch.nn.DataParalle 4.5.2 torch.distributed 4.5.3 torch.utils.checkpoint im ...

  10. Jmeter小白使用攻略

    <Jmeter小白使用攻略> 一.主界面 二.如何测试一个接口