拦截器

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. 第138篇:了解HTTP协议(TCP/IP协议,DNS域名解析,浏览器缓存)

    好家伙,发现自己的网络知识十分匮乏,赶紧补一下   这里先举个我生活中的例子 欸,作业不会写了,上网搜一下 用edge浏览器上bing必应搜一下(百度广告太多了,真不想用百度举例子)   假设这是我们 ...

  2. Python OOP面向对象编程

    OOP 思想: 以模块思想解决工程问题 面向过程 VS 面向对象 由面向过程转向面向对象 例子,我要开一个学校,叫XXX 讲师 学生 班主任 教室 学校 常用名词 OO:面向对象 OOA: 分析 OO ...

  3. LeetCode 周赛 344(2023/05/07)手写递归函数的固定套路

    本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 大家好,我是小彭. 今天下午有力扣杯战队赛,不知道官方是不是故意调低早上周赛难度给选手们练练手. 往期周赛回 ...

  4. pytest测试实战和练习

    开头 经过前面几章的学习,这时候要来个测试实战会比较好巩固一下学过的知识 任务要求 1.实现计算器(加法,除法)的测试用例 2.使用数据驱动完成测试用例的自动生成 3.在调用测试方法之前打印[开始计算 ...

  5. SDK日志上传性能优化

    问题描述 在SDK初始化时,会在init方法中开启一个倒计时,在5s倒计时结束后使用子线程将本地保存的历史日志信息上传到后台. 因业务需要,在日志在发送上传前,对日志数据上传时需要对日志数据做编码和特 ...

  6. 【GiraKoo】Android监听屏幕尺寸变化通知

    [GiraKoo]Android监听屏幕尺寸变化通知 Android系统中存在多种情况可能导致屏幕尺寸发生变化.例如:横竖屏切换,虚拟按键,分屏,键盘弹出等. App有的时候需要了解屏幕的真实尺寸,D ...

  7. 计算机网络OSI七层参考模型和tcp/udp五层参考模型

    计算机网络OSI七层参考模型和tcp/udp五层参考模型 目录 一.OSI七层参考模型和TCP/UDP五层参考模型 1.应用层 2.表示层 3.会话层 4.传输层 5.网络层 6.数据链路层 7.物理 ...

  8. remote: HTTP Basic:Access denied fatal:Authentication failed for

    近来在一天新电脑上面使用git pull 一个项目,老是提示 Access denied, 找了许多方法,ssh key这些都配置了还是不行,当时别提有多尬 看嘛这就是pull 时的提示 // *** ...

  9. 研究NIST 800-53B信息系统和组织的控制基线

    简介 800-53B是800-53的定制版本.为低.中.高影响的系统提供了安全与隐私控制手段.对于所有企业,定制控制手段不是强制的,必须的,可以参考NIST SP 800-37(800-37)提供了关 ...

  10. Python asyncio之协程学习总结

    实践环境 Python 3.6.2 什么是协程 协程(Coroutine)一种电脑程序组件,该程序组件通过允许暂停和恢复任务,为非抢占式多任务生成子程序.协程也可以简单理解为协作的程序,通过协同多任务 ...