在 Spring Boot 中使用 Filters 实现请求过滤和预处理

 ​

 博客主页:     南来_北往

系列专栏:Spring Boot实战


什么是过滤器

过滤器(Filter)是一种在Web应用中用于拦截和处理HTTP请求和响应的对象

在Java Web开发中,过滤器是实现特定功能,如认证、日志记录和字符编码处理的重要工具。具体如下:

  1. 过滤器的基本概念
    • 定义:过滤器是一种可以动态地拦截传入的请求和传出的响应,并对这些请求和响应进行预处理和后处理的对象。
    • 作用:过滤器可以检查和修改请求头和响应头、处理cookies、验证用户提交的数据等。
  2. 过滤器的工作原理
    • 工作流程:当一个请求到达服务器时,它会首先通过过滤器链,每个过滤器都有机会对请求进行处理。如果请求通过了所有过滤器的检验,它最终会到达目标资源,如servlet或JSP页面。
    • 请求处理:在过滤器中可以通过修改请求对象来实现对请求数据的预处理,例如,可以对输入数据进行解码或者验证。
    • 响应处理:在放行请求后,还可以在过滤器中修改返回给用户的响应数据,例如,对输出数据进行编码或者压缩。
  3. 过滤器的生命周期
    • 初始化init方法在过滤器创建时被调用,用于初始化操作。这个方法只运行一次,一般用来读取配置文件和初始化资源。
    • 过滤请求doFilter方法是实际执行过滤操作的地方,每次请求经过过滤器时都会被调用。在这个方法中可以实现具体的过滤逻辑,并通过FilterChain对象决定是否将请求传递到下一个过滤器或者目标资源。
    • 销毁destroy方法在过滤器销毁之前被调用,用于释放资源。这也是只运行一次的方法,通常用于清理操作。
  4. 过滤器的使用场景
    • 身份验证:用于检查用户是否已经登录,确保只有合法用户才能访问受保护的资源。
    • 日志记录:记录每个请求的信息,如IP地址、访问时间等,有助于网站管理和安全监控。
    • 字符编码处理:解决不同字符集之间的兼容问题,避免出现乱码。
    • 输入数据验证:对用户提交的数据进行格式和有效性验证,防止非法输入导致的安全问题。
  5. 如何配置和使用过滤器
    • 注解方式:通过@WebFilter注解直接在过滤器类上指定拦截路径,这种方法更简单、直观。
    • XML配置:在web.xml文件中配置<filter><filter-mapping>元素,以定义过滤器及其应用场景。

综上所述,过滤器在Web应用中起着至关重要的作用,从请求预处理到响应后处理,都能有效地提高应用的安全性、可用性和用户体验。对于开发人员而言,掌握过滤器的使用是提升Web应用质量的重要手段。

为什么我们需要过滤器

过滤器在Web开发中扮演着至关重要的角色,它们用于增强、控制和修改HTTP请求和响应的处理。具体如下:

  1. 为什么需要过滤器
    • 提高代码重用性:通过使用过滤器可以避免在多个Servlet或JSP页面中重复编写相同的代码,从而简化了代码维护并减少了冗余。
    • 实现全局功能:过滤器可以全局处理所有请求,从而统一实现如字符编码处理、敏感词汇过滤等功能。
    • 增强安全性:通过身份验证和授权,过滤器能够阻止未经授权的用户访问受保护的资源,提升应用的安全性。
    • 提供更好的用户体验:例如,过滤器可以用于网站的统一登录功能,用户只需一次登录即可访问所有受保护的资源,而无需多次认证。
  2. 过滤器的工作原理及生命周期
    • 工作流程:当一个请求到达服务器时,它会首先通过过滤器链,每个过滤器都有机会对请求进行处理。如果请求通过了所有过滤器的检验,它最终会到达目标资源,如servlet或JSP页面。
    • 请求处理:在过滤器中可以通过修改请求对象来实现对请求数据的预处理,例如,对输入数据进行解码或验证。
    • 响应处理:在放行请求后,还可以在过滤器中修改返回给用户的响应数据,例如,对输出数据进行编码或压缩。
    • 生命周期方法:过滤器的生命周期包括initdoFilterdestroy三个方法。init方法在过滤器创建时调用,用于初始化操作;doFilter方法在实际请求处理中被调用;destroy方法在过滤器销毁前调用,用于释放资源。
  3. 过滤器的主要应用场景
    • 字符编码处理:通过过滤器可以统一设置请求和响应的字符编码,避免出现乱码问题。这在处理不同语言环境的应用中尤其重要。
    • 权限验证:过滤器可以检查用户是否已经登录或是否有权访问某个资源。这样,只有合法用户才能访问受保护的资源。
    • 日志记录:过滤器可以记录每个请求的信息,如IP地址、访问时间等,有助于网站管理和安全监控。
    • 输入数据验证:过滤器可以对用户提交的数据进行格式和有效性验证,防止非法输入导致的安全问题。
    • 敏感信息过滤:过滤器可以过滤掉请求和响应中的敏感信息,如SQL注入攻击的字符串,确保数据传输的安全。
  4. 如何在Spring Boot中使用过滤器
    • 创建过滤器类:实现javax.servlet.Filter接口,并覆盖doFilter方法以定义过滤器的逻辑。在doFilter方法中,可以对请求和响应进行处理,并通过调用FilterChain.doFilter()将请求传递给下一个过滤器或目标Servlet。
    • 注册过滤器:使用@WebFilter注解将过滤器类标记为过滤器,并通过urlPatterns属性指定要拦截的URL模式。如果不使用@WebFilter注解,也可以通过在Spring Boot配置类中使用FilterRegistrationBean来注册过滤器。先创建一个FilterRegistrationBean实例,然后设置过滤器实例,添加URL模式,并设置优先级。
  5. 过滤器与拦截器的区别
    • 处理范围:过滤器主要作用于Servlet容器层次,可以拦截所有到达Web应用的请求;而拦截器则作用于Spring MVC框架内,只能拦截由DispatcherServlet管理的请求。
    • 执行顺序:过滤器的执行顺序依赖于它们在web.xml中的配置顺序或通过@WebFilter注解声明的顺序;拦截器的执行顺序则依赖于在Spring配置文件中的声明顺序。
    • 功能实现:过滤器更侧重于请求的预处理和响应的后处理,比如字符编码处理、文件上传处理等;拦截器则更侧重于视图渲染前的控制器执行流程,如权限检查、表单验证等。

综上所述,过滤器在Web应用的开发中起着至关重要的作用。从请求预处理到响应后处理,过滤器都能有效地提高应用的安全性、可用性和用户体验。对于开发人员而言,掌握过滤器的使用是提升Web应用质量的重要手段。

创建过滤器

要在Spring Boot中创建过滤器,您可以实现javax.servlet.Filter接口或扩展OncePerRequestFilter类。OncePerRequestFilter确保您的过滤器每个请求只执行一次。

@RestController@RequestMapping("/customer")public class CustomerController {@GetMappingpublic String getMessage(){return "welcome to filter session";}}@Component@Slf4jpublic class MessageFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {log.info("[MessageFilter] - Inside doFilter method");log.info("Local Port : " + request.getLocalPort());log.info("Server Name : " + request.getServerName());HttpServletRequest httpServletRequest = (HttpServletRequest) request;log.info("Method Name : " + httpServletRequest.getMethod());log.info("Request URI : " + httpServletRequest.getRequestURI());log.info("Servlet Path : " + httpServletRequest.getServletPath());chain.doFilter(request, response);}}

过滤器的顺序

过滤器的应用顺序可以通过@Order注解或

@Component@Slf4j@Order(2)public class MessageFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {log.info("[MessageFilter] - Inside doFilter method");log.info("Local Port : " + request.getLocalPort());log.info("Server Name : " + request.getServerName());HttpServletRequest httpServletRequest = (HttpServletRequest) request;log.info("Method Name : " + httpServletRequest.getMethod());log.info("Request URI : " + httpServletRequest.getRequestURI());log.info("Servlet Path : " + httpServletRequest.getServletPath());chain.doFilter(request, response);}}@Component@Slf4j@Order(1)public class ProductFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {log.info("[ProductFilter] - Inside doFilter method");log.info("Local Port : " + request.getLocalPort());log.info("Server Name : " + request.getServerName());HttpServletRequest httpServletRequest = (HttpServletRequest) request;log.info("Method Name : " + httpServletRequest.getMethod());log.info("Request URI : " + httpServletRequest.getRequestURI());log.info("Servlet Path : " + httpServletRequest.getServletPath());chain.doFilter(request, response);}}

注意:如果您只想打印MessageFilter并跳过ProductFilter

要在访问/customer API时仅显示MessageFilter的日志,您需要有条件地绕过ProductFilter/customer端点的过滤。您可以通过修改ProductFilter来跳过特定端点的过滤来实现这一点。

@Component@Slf4j@Order(1) // 确保此过滤器在MessageFilter之前执行public class ProductFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest httpServletRequest = (HttpServletRequest) request;String requestURI = httpServletRequest.getRequestURI();if ("/customer".equals(requestURI)) {chain.doFilter(request, response);return; // 跳过过滤器的其余部分}log.info("[ProductFilter] - Inside doFilter method");log.info("Local Port : " + request.getLocalPort());log.info("Server Name : " + request.getServerName());log.info("Method Name : " + httpServletRequest.getMethod());log.info("Request URI : " + requestURI);log.info("Servlet Path : " + httpServletRequest.getServletPath());chain.doFilter(request, response);}}

 注册过滤器

@Configurationpublic class FilterConfig {@Beanpublic FilterRegistrationBean<MessageFilter> loggingFilter(){FilterRegistrationBean<MessageFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new MessageFilter());registrationBean.addUrlPatterns("/customer/*"); // 如果需要,指定URL模式return registrationBean;}}

 OncePerRequestFilter

public class ProductFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {log.info("[ProductFilter] - Inside doFilter method");log.info("Local Port : " + request.getLocalPort());log.info("Server Name : " + request.getServerName());HttpServletRequest httpServletRequest = (HttpServletRequest) request;log.info("Method Name : " + httpServletRequest.getMethod());log.info("Request URI : " + httpServletRequest.getRequestURI());log.info("Servlet Path : " + httpServletRequest.getServletPath());filterChain.doFilter(request, response);}}

简单案例

1、建一个新的Java类,并实现javax.servlet.Filter接口。例如,创建一个名为MyFilter的类:

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化代码(可选)}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;// 在这里可以对请求进行预处理操作,例如检查请求头、参数等// 继续执行过滤器链中的下一个过滤器或目标资源chain.doFilter(request, response);// 在这里可以对响应进行后处理操作,例如修改响应头、内容等}@Overridepublic void destroy() {// 销毁代码(可选)}
}

2、在Spring Boot应用程序的配置类上添加@Configuration注解,并在该类中定义一个方法,该方法返回一个带有@Bean注解的FilterRegistrationBean实例。这将注册你的过滤器并将其添加到过滤器链中。

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FilterConfig {@Beanpublic FilterRegistrationBean<MyFilter> myFilter() {FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new MyFilter());registrationBean.addUrlPatterns("/api/*"); // 设置过滤器应用于哪些URL模式registrationBean.setOrder(1); // 设置过滤器的顺序(数字越小,优先级越高)return registrationBean;}
}

在上面的示例中,我们为MyFilter设置了URL模式/api/*,这意味着它将应用于所有以/api/开头的请求。你可以根据需要调整URL模式。

3、现在,每当有匹配的请求到达时,MyFilter就会被调用,你可以在doFilter方法中编写自定义的请求过滤和预处理逻辑。同样地,你也可以在响应返回给客户端之前对其进行后处理。

这样,你就成功地在Spring Boot应用程序中实现了请求过滤和预处理功能。记得根据你的需求调整过滤器的逻辑和配置。

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

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

相关文章

X-AnyLabeling标注软件使用方法

第一步 下载 官方X-AnyLabeling下载地址 github&#xff1a;X-AnyLabeling 第二步 配置环境 使用conda创建新的虚拟环境 conda create -n xanylabel python3.8进入环境 conda activate xanylabel进入X-AnyLabeling文件夹内&#xff0c;运行下面内容 依赖文件系统环境运行环…

MyBatisPlus复习

目录 自定义sql swagger工具 IService批量新增 代码生成器 DB静态工具&#xff0c;hutool工具 逻辑删除 枚举处理器 Json处理器 分页 自定义sql swagger工具 IService批量新增 代码生成器 DB静态工具&#xff0c;hutool工具 逻辑删除 枚举处理器 Json处理器 分页

ks滑块验证码逆向分析与python识别

文章目录 1. 写在前面3. 接口分析3. 算法实现 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python…

大模型技术:发展历程、经典模型、微调与应用[更新中...]

文章目录 一、预训练语言模型发展历程二、经典的Pre-trained任务2.1 Masked Language Modeling2.2 Next Sentence Prediction 三、Task-specific Fine-tuning 任务3.1 Single-text Classification (单句分类)3.2 Sentence-pair Classification (句子匹配/成对分类)3.3 Span Tex…

谷粒商城实战笔记-71-商品服务-API-属性分组-前端组件抽取父子组件交互

文章目录 一&#xff0c;一次性创建所有的菜单二&#xff0c;开发属性分组界面1&#xff0c;左侧三级分类树形组件2&#xff0c;右侧分组列表3&#xff0c;左右两部分通信3.1 子组件发送数据3.2&#xff0c;父组件接收数据 Vue的父子组件通信父组件向子组件传递数据子组件向父组…

【BUG】已解决:The above exception was the direct cause of the following exception:

The above exception was the direct cause of the following exception: 目录 The above exception was the direct cause of the following exception: 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c…

【杰理蓝牙开发】AC695x 音频部分

本文主要记录 杰理蓝牙audio接口的使用&#xff0c;包括ADC和DAC原理的介绍和API接口的使用。 【杰理蓝牙开发】AC695x 音频部分 0. 个人简介 && 授权须知1. ADC【音频数据采集】硬件部分1.1 单片机引脚1.2 硬件电路设计1.3 MIC 输入通路解释 2. 【DAC】音频信号编解码…

Super 4PCS配准算法

Nicolas Mellado&#xff0c;CNRS&#xff08;Centre national de la recherche scientifique&#xff0c;法国国家科学研究中心&#xff09;的研究员&#xff0c;在IRIT&#xff08;Institut de Recherche en Informatique de Toulouse&#xff0c;图卢兹计算机科学研究所&…

SAPUI5基础知识20 - 对话框和碎片(Dialogs and Fragments)

1. 背景 在 SAPUI5 中&#xff0c;Fragments 是一种轻量级的 UI 组件&#xff0c;类似于视图&#xff08;Views&#xff09;&#xff0c;但它们没有自己的控制器&#xff08;Controller&#xff09;。Fragments 通常用于定义可以在多个视图中重用的 UI 片段&#xff0c;从而提…

linux系统安装pytorch_中文地址命名实体识别案例

命名实体有关文章参考这篇文章 中文地址命名实体识别训练和预测 win10系统安装cuda环境参考这篇文章 搭建Pytorch的GPU环境超详细 1、下载python https://www.python.org/downloads/release/python-368/ 2、下载python包 https://pypi.org/search/?q=transformers 1、搜…

如何录制电脑内部声音?全方位介绍电脑录音软件:8款在线录音!(2024重新整理)

如何录制电脑内部声音&#xff1f;不管是娱乐圈还是现实生活&#xff0c;【录音】这个功能的重要性不言而喻。而电脑录音已在影视配音、音视频剪辑、会议记录、在线教育等多个领域发光发热&#xff01; 本文将为您推荐8款电脑录音软件&#xff0c;并详细介绍电脑录音的多种方式…

Python番外篇:变量是盒子还是标签

引言 前面通过几十篇文章&#xff0c;大概把Python的一些比较实用的基础做了一些介绍&#xff0c;学会这些&#xff0c;基本能应付日常的小的需求开发了&#xff0c;写一些小工具&#xff0c;提高工作的处理效率。 接下来&#xff0c;准备开始进入一个新的篇章&#xff0c;也…

C#如何引用dll动态链接库文件的注释

1、dll动态库文件项目生成属性中要勾选“XML文档文件” 注意&#xff1a;XML文件的名字切勿修改。 2、添加引用时XML文件要与DLL文件在同一个目录下。 3、如果要是添加引用的时候XML不在相同目录下&#xff0c;之后又将XML文件复制到相同的目录下&#xff0c;需要删除引用&am…

当设计模式牵手LLM

模版方法模式 何为模版设计模式 想象一下 如果我们要泡一杯茶 我们要循序渐进地 煮水温杯注水浸茶茶水入杯加点配料 如此&#xff0c;泡茶的工序就完成了&#xff0c;那么模板方法模式&#xff0c;相信各位也有了一定的概念&#xff1a;定义了一个算法的骨架&#xff0c;而…

UDP的报文结构及其注意事项

1. 概述 UDP&#xff08;User Datagram Protocol&#xff09;是一种无连接的传输层协议&#xff0c;它提供了一种简单的数据传输服务&#xff0c;不保证数据的可靠传输。在网络通信中&#xff0c;UDP通常用于一些对实时性要求较高、数据量较小、传输延迟较低的应用&#xff0c…

【JVM基础07】——类加载器-什么是类加载器?类加载器有哪些?双亲委派了解吗?

目录 1- 引言&#xff1a;类加载器1-1 类加载器是什么&#xff1f;(What)1-2 为什么要用类加载器&#xff1f; 作用&#xff1a;类加载的过程&#xff1f;(Why) 2- ⭐核心&#xff1a;类加载器详解(How)2-1 类加载器分类2-2 什么是双亲委派模型&#xff1f;2-3 为什么采用双亲委…

Pytorch基础:Tensor的squeeze和unsqueeze方法

相关阅读 Pytorch基础https://blog.csdn.net/weixin_45791458/category_12457644.html?spm1001.2014.3001.5482 在Pytorch中&#xff0c;squeeze和unsqueeze是Tensor的一个重要方法&#xff0c;同时它们也是torch模块中的一个函数&#xff0c;它们的语法如下所示。 Tensor.…

【SpringBoot】1 Gitee

本项目 Gitee 地址&#xff1a;https://gitee.com/Lin_DH/system idea中可能装个gitee的插件&#xff0c;这样操作起来比较方便。 1&#xff09;登录 Gitee 官网&#xff08;https://gitee.com/&#xff09;&#xff0c;新建仓库。 2&#xff09;复制新建的 Gitee 仓库地址&am…

Unity3D之TextMeshPro使用

文章目录 1. TextMeshPro简介2. TextMeshPro创建3. TextMeshPro脚本中调用4. TextMeshPro字体设置及中文支持过程中出现的一些问题 1. TextMeshPro简介 【官网文档】https://docs.unity.cn/cn/2020.3/Manual/com.unity.textmeshpro.html TextMeshPro 是 Unity 的最终文本解决…

软件测试---Linux

Linux命令使用&#xff1a;为了将来工作中与服务器设备进行交互而准备的技能&#xff08;远程连接/命令的使用&#xff09;数据库的使用&#xff1a;MySQL&#xff0c;除了查询动作需要重点掌握以外&#xff0c;其他操作了解即可什么是虚拟机 通过虚拟化技术&#xff0c;在电脑…