Spring Boot 使用过滤器、拦截器、监听器

前言

作用

  • 过滤器(Filter):当有一堆请求,只希望符合预期的请求进来。
  • 拦截器(Interceptor):想要干涉预期的请求。
  • 监听器(Listener):想要监听这些请求具体做了什么。

区别

过滤器是在请求进入容器后,但还没有进入 Servlet 之前进行预处理的。如下图所示。

拦截器是在请求进入控制器(Controller) 之前进行预处理的。

虚线内就是过滤器和拦截器的作用范围:

过滤器依赖于 Servlet 容器,而拦截器依赖于 Spring 的 IoC 容器,因此可以通过注入的方式获取容器当中的对象。

监听器用于监听 Web 应用中某些对象的创建、销毁、增加、修改、删除等动作,然后做出相应的处理。

过滤器

  • 过滤敏感词汇(防止sql注入)
  • 设置字符编码
  • URL级别的权限访问控制
  • 压缩响应信息

过滤器的创建和销毁都由 Web 服务器负责,Web 应用程序启动的时候,创建过滤器对象,为后续的请求过滤做好准备。

过滤器可以有很多个,一个个过滤器组合起来就成了 FilterChain,也就是过滤器链。

在 Spring 中,过滤器都默认继承了 OncePerRequestFilter,顾名思义,OncePerRequestFilter 的作用就是确保一次请求只通过一次过滤器,而不重复执行。

接下来我们通过继承 OncePerRequestFilter 来实现 JWT 登录授权过滤。

 

public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain chain) throws ServletException, IOException {// 从客户端请求中获取 JWTString authHeader = request.getHeader(this.tokenHeader);// 该 JWT 是我们规定的格式,以 tokenHead 开头if (authHeader != null && authHeader.startsWith(this.tokenHead)) {// The part after "Bearer "String authToken = authHeader.substring(this.tokenHead.length());// 从 JWT 中获取用户名String username = jwtTokenUtil.getUserNameFromToken(authToken);LOGGER.info("checking username:{}", username);// SecurityContextHolder 是 SpringSecurity 的一个工具类// 保存应用程序中当前使用人的安全上下文if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {// 根据用户名获取登录用户信息UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);// 验证 token 是否过期if (jwtTokenUtil.validateToken(authToken, userDetails)) {// 将登录用户保存到安全上下文中UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails,null, userDetails.getAuthorities());authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(authentication);}}}chain.doFilter(request, response);}
}

新建一个 Web 项目 codingmore-filter-interceptor-listener。

添加一个过滤器 MyFilter :

@WebFilter(urlPatterns = "/*", filterName = "myFilter")
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {Filter.super.init(filterConfig);}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {long start = System.currentTimeMillis();chain.doFilter(request,response);System.out.println("Execute cost="+(System.currentTimeMillis()-start));}@Overridepublic void destroy() {Filter.super.destroy();}
}

@WebFilter 注解用于将一个类声明为过滤器,urlPatterns 属性用来指定过滤器的 URL 匹配模式,filterName 用来定义过滤器的名字。

MyFilter 过滤器的逻辑非常简单,重写了 Filter 的三个方法,在 doFilter 方法中加入了时间戳的记录。

然后我们在项目入口类上加上 @ServletComponentScan 注解,这样过滤器就会自动注册。

启动服务器,访问任意的 URL。

拦截器

  • 登录验证,判断用户是否登录
  • 权限验证,判断用户是否有权限访问资源,如校验token
  • 日志记录,记录请求操作日志(用户ip,访问时间等),以便统计请求访问量
  • 处理cookie、本地化、国际化、主题等
  • 性能监控,监控请求处理时长等

我们来写一个简单的拦截器 LoggerInterceptor:

@Slf4j
public class LoggerInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info("preHandle{} ...." ,request.getRequestURI());}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}}

一个拦截器必须实现 HandlerInterceptor 接口,preHandle 方法是 Controller 方法调用前执行,postHandle  是 Controller 方法正常返回后执行,afterCompletion 方法无论 Controller 方法是否抛异常都会执行。

只有 preHandle 返回 true 的话,其他两个方法才会执行。

如果 preHandle 返回 false 的话,表示不需要调用Controller方法继续处理了,通常在认证或者安全检查失败时直接返回错误响应。

再来一个 InterceptorConfig 对拦截器进行配置:

/*** @ClAssName InterceptorConfig* @Description TOOO* @Author soshi是神仙* @Date 2024/3/27 18:{MINUTE}*/
@Configuration
public class InterceptorConfig  implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {WebMvcConfigurer.super.addInterceptors(registry);registry.addInterceptor(new LoggerInterceptor()).addPathPatterns("/**");}
}

@Configuration 注解用于定义配置类,干掉了以往 Spring 繁琐的 xml 配置文件。

编写一个用于被拦截的控制器 MyInterceptorController:

@RestController
@RequestMapping("/myinterceptor")
public class MyInterceptorController {@RequestMapping("/hello")public  String hello(){return "测试拦截器的使用";}
}

@RestController 注解相当于 @Controller + @ResponseBody 注解,@ResponseBody 注解用于将 Controller 方法返回的对象,通过适当的 HttpMessageConverter 转换为指定格式后,写入到 Response 对象的 body 数据区,通常用来返回 JSON 或者 XML 数据,返回 JSON 数据的情况比较多。

启动服务器,访问 http://localhost:8080/myinterceptor/hello

在控制台可以看到拦截器中的日志信息

无论是过滤器还是拦截器,都属于AOP(面向切面编程)思想的具体实现。除了这两种实现之外,还有另一种更灵活的AOP实现技术,即 Aspect,在实战项目里,你可以看到 Aspect 具体实现。

比如说统一日志切面 WebLogAspect,就是用来记录请求信息的。

@Aspect
@Component
@Order(1)
public class WebLogAspect {private static final Logger LOGGER = LoggerFactory.getLogger(WebLogAspect.class);@Pointcut("execution(public * com.codingmore.controller.*.*(..))")public void webLog() {}@Before("webLog()")public void doBefore(JoinPoint joinPoint) throws Throwable {}@AfterReturning(value = "webLog()", returning = "ret")public void doAfterReturning(Object ret) throws Throwable {}@Around("webLog()")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {long startTime = System.currentTimeMillis();//获取当前请求对象ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();webLog.setStartTime(startTime);webLog.setUri(request.getRequestURI());logMap.put("parameter",webLog.getParameter());logMap.put("spendTime",webLog.getSpendTime());logMap.put("description",webLog.getDescription());LOGGER.info("{}", JSONUtil.parse(webLog));return result;}/*** 根据方法和传入的参数获取请求参数*/private Object getParameter(Method method, Object[] args) {}
}

监听器

根据监听对象可以把监听器分为 3 类:

  • ServletContext:对应应用 application,整个 Web 服务器中只有一个,Web 服务器关闭时销毁。可用于数据缓存,例如结合redis,在Web服务创建时从数据库拉取数据到缓存服务器。
  • HttpSession: 对应会话 session,在会话建立时创建,一端会话关闭时销毁。可用于获取在线用户数量。
  • ServletRequest:对应 request,客户端发送请求时创建,一同创建的还有 response,用于封装请求数据,在一次请求处理完成时销毁。可用于封装用户信息。

新建一个 MyListener:

@WebListener
public class MyListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {ServletContextListener.super.contextInitialized(sce);System.out.println("上下文创建");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println("上下文销毁");}

@WebListener 注解用于将一个类声明为监听器,同样干掉了 web.xml 文件。

ServletContextListener 能够监听整个 Web 应用程序的生命周期。当 Web 应用启动时触发 contextInitialized 方法,关闭时触发 contextDestroyed 方法。

在 Intellij IDEA 中重启服务的时候,可以在控制台看到如下信息:

不过需要注意的是,在 Intellij IDEA 中直接关闭进程无法看到 contextDestroyed 被调用的消息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/291721.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【剑指offer】顺时针打印矩阵

题目链接 acwing leetcode 题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。 数据范围矩阵中元素数量 [0,400]。 输入: [ [1, 2, 3, 4], [5, 6, 7, 8], [9,10,11,12] ] 输出:[1,2,3,4,8,12,11,10,9,5,6,7] 解题 …

百度蜘蛛池平台在线发外链-原理以及搭建教程

蜘蛛池平台是一款非常实用的SEO优化工具,它可以帮助网站管理员提高网站的排名和流量。百度蜘蛛池原理是基于百度搜索引擎的搜索算法,通过对网页的内容、结构、链接等方面进行分析和评估,从而判断网页的质量和重要性,从而对网页进行…

Midjourney AI绘图工具介绍及使用

介绍 Midjourney是一款目前被誉为最强的AI绘图工具。只要输入想到的文字,就能通过人工智能产出相对应的图片。 官网只是宣传和登录入口,提供个人主页、订阅管理等功能,Midjourney实际的绘画功能,是在另外一个叫discord的产品中实…

C++多线程:线程的创建、join、detach、joinable方法(二)

1、线程的开始与结束 程序运行起来,生成一个进程,该进程所持有的主线程开始自动运行,main主线程运行完所有的代码从main函数中返回表示整个进程运行完毕,标志着主线程和进程的死亡,等待操作系统回收资源,因…

论文笔记:Retrieval-Augmented Generation forAI-Generated Content: A Survey

北大202402的RAG综述 1 intro 1.1 AICG 近年来,人们对人工智能生成内容(AIGC)的兴趣激增。各种内容生成工具已经精心设计,用于生产各种模态下的多样化对象 文本&代码:大型语言模型(LLM)…

Linux网络配置(超详细)

Linux网络配置大全 Linux网络配置一.网络地址配置网络地址查看–ifconfig使用网络配置命令设置网络接口参数-ifconfig禁用(临时)或者重新激活网卡设置虚拟网络接口 修改网络配置文件网络接口配置文件 IP命令详解OPTIONS选项OBJECT对象 ip link 二、获取和修改主机名hostname查看…

E5063A是德科技E5063A网络分析仪

181/2461/8938产品概述: Keysight E5063A 是一款低成本网络分析仪,可为测试天线、电缆、滤波器和 PCB 等简单无源元件提供优化的性能和功能。Keysight E5063A 为您的企业提供价格和性能之间的最佳平衡,以满足您的业务和技术要求。它利用行业…

QT_day4:对话框

1、完善对话框,点击登录对话框,如果账号和密码匹配,则弹出信息对话框,给出提示”登录成功“,提供一个Ok按钮,用户点击Ok后,关闭登录界面,跳转到其他界面 如果账号和密码不匹配&…

Trapcode Particular---打造惊艳粒子效果

Trapcode Particular是Adobe After Effects中的一款强大3D粒子系统插件,其能够创造出丰富多样的自然特效,如烟雾、火焰和闪光,以及有机的和高科技风格的图形效果。Trapcode Particular功能丰富且特色鲜明,是一款为Adobe After Eff…

Elasticsearch:语义搜索即服务处于卓越搜索的中心

作者:来自 Elastic Sherry Ger, Stephen Brown 对于许多企业来说,搜索卓越中心(center of excellence - COE)向其用户提供搜索服务,从不同的数据源中整理知识,并将搜索功能集成到其内部和外部应用程序中。…

第4章.精通标准提示,引领ChatGPT精准输出

标准提示 标准提示,是引导ChatGPT输出的一个简单方法,它提供了一个具体的任务让模型完成。 如果你要生成一篇新闻摘要。你只要发送指示词:汇总这篇新闻 : …… 提示公式:生成[任务] 生成新闻文章的摘要: 任务&#x…

完整部署一套k8s-v.1.28.0版本的集群

一、系统情况 虚拟机版本:esxi 6.7 系统版本:centos7.9_2009_x86 配置:4核8G(官网最低要求2核2G) 192.168.0.137 master节点 192.168.0.139 node2节点 192.168.0.138 node1节点(节点扩容练习&#xf…

(五)ROS2学习--创建调用其它包接口的一个发布者

这里写自定义目录标题 一、背景二、构建步骤1. 构建项目包2. 创建消息接口3. 修改“package.xml”4. 修改"src/smart_car/CMakeLists.txt"5. 创建发布者程序 三、编译及验证1. 编译2. 验证 一、背景 主机:Ubuntu20.04 介绍:基于上一篇&#x…

大话设计模式之工厂模式

工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的最佳方式,而无需指定将要创建的对象的确切类。通过使用工厂模式,我们可以将对象的创建和使用分离,从而使代码更具灵活性和可维护性。…

音视频处理 - 音频概念详解,码率,采样率,位深度,声道,编码

1. 音频采样 与视频不同,音频的最小单位不是一帧,而是一个采样。 采样是当前一刻声音的声音样本,样本需要经过数字转换才能存储为样本数据。 真实声音是连续的,但是在计算机中,声音是离散且均匀的声音样本。 2. 位深…

22 多态

目录 多态的概念多态的定义及实现抽象类多态的原理单继承和多继承关系中的虚函数表继承和多态常见的面试问题 前言 需要声明的,下面的代码和解释的哦朴实vs2013x86环境,涉及指针是4bytes,如果要其他平台下,部分代码需要改动。比…

ttkbootstrap界面美化系列之Notebook(四)

在简单的界面设计中,Notebook也是常用的组件之一,Notebook组件的引入可以根据标签来切换不同的界面。使得界面更有层次感,不必都挤在一个界面上。在tkinter中就有Notebook组件,在ttkbootstrap中,同样也对Notebook进行了…

四、Yocto创建静态IP和VLAN(基于raspiberrypi 4B)

Yocto创建VLAN配置 在车载域控中很多时候需要创建VLAN,本小节记录如何为yocto构建出来的image自动化创建静态IP以及VLAN。 关于各种VLAN的配置参考:VLAN 1. ubuntu系统中使用netplan创建VLAN 正常情况下我们在ubuntu系统中可以通过netplan来自动化创建…

会话跟踪技术(Session 以及Cookie)

一: 前提概要 1>会话: 会话指的是用户打开浏览器, 访问某些web服务器资源的时候, 会话就会进行建立, 直到有一方断开, 那么会话才会结束, 需要注意的一点是, 一次的会话可以有多次的请求以及响应 2>会话跟踪: 是一种用于维护浏览器状态的方法, 服务器需要识别多次的请求,…

CTF题型 php://filter特殊编码绕过小汇总

CTF题型 php://filter特殊编码绕过小汇总 文章目录 CTF题型 php://filter特殊编码绕过小汇总特殊编码base64编码string过滤器iconv字符集 例题1.[Newstarctf 2023 week2 include]2.[Ctfshow web 117] php://filter 是一个伪协议,它允许你读取经过过滤器处理的数据流…