当前位置:首页 > 学海无涯 > 正文内容

Spring Boot 过滤器入门:从概念到实战配置

清羽天3个月前 (09-15)学海无涯37


在 Web 开发中,过滤器(Filter)是处理 HTTP 请求和响应的重要组件,它能在请求到达控制器前、响应返回客户端前进行拦截和处理。比如日志记录、权限验证、字符编码转换等场景,都离不开过滤器的身影。本文将带大家从零开始,掌握 Spring Boot 中过滤器的入门知识和完整设置流程。

一、过滤器基础:你需要知道的核心概念

1. 过滤器的作用

过滤器本质是一个实现了javax.servlet.Filter接口的 Java 类,它工作在Servlet 容器层面,生命周期由容器管理,主要功能包括:
  • 请求拦截:在请求到达 Controller 前,修改请求参数、头部信息,或直接拒绝请求(如未登录用户拦截);

  • 响应处理:在响应返回客户端前,修改响应内容、设置 Cookie 或响应头(如统一设置跨域头);

  • 通用处理:全局日志记录(记录请求 URL、耗时)、统一字符编码(防止乱码)等。

2. 过滤器的生命周期

Spring Boot 中过滤器的生命周期与 Servlet 容器一致,分为 3 个阶段:
  1. 初始化(init):容器启动时调用init(FilterConfig),初始化过滤器配置(如读取参数),仅执行一次;

  1. 拦截处理(doFilter):每次请求匹配时调用,核心逻辑所在,通过FilterChain传递请求(chain.doFilter(request, response));

  1. 销毁(destroy):容器关闭时调用destroy(),释放资源(如关闭日志流),仅执行一次。

二、Spring Boot 过滤器实战:3 种创建与配置方式

Spring Boot 简化了传统 Java Web 中过滤器的配置(无需web.xml),主流有注解驱动Java 配置类@Component 扫描三种方式,下面逐一讲解。

方式 1:@Component + @WebFilter(最简单,适合单过滤器)

这种方式通过注解自动注册过滤器,无需额外配置,适合单个过滤器的场景。

步骤 1:创建过滤器类

新建LogFilter类,实现Filter接口,添加@Component(让 Spring 扫描)和@WebFilter(指定拦截路径):
import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import java.io.IOException;// 标记为Spring组件,自动注入容器@Component// 配置拦截路径:/* 表示拦截所有请求@WebFilter(urlPatterns = "/*", filterName = "logFilter")public class LogFilter implements Filter {private static final Logger logger = LoggerFactory.getLogger(LogFilter.class);// 初始化:容器启动时执行一次@Overridepublic void init(FilterConfig filterConfig) throws ServletException {logger.info("LogFilter初始化...");}// 核心拦截逻辑:每次请求匹配时执行@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {// 1. 处理请求前:记录请求信息long startTime = System.currentTimeMillis();logger.info("请求URL:{},开始时间:{}",((javax.servlet.http.HttpServletRequest) request).getRequestURI(),startTime);// 2. 放行请求:让请求继续流向Controller(必须调用,否则请求会被拦截)chain.doFilter(request, response);// 3. 处理响应后:记录耗时long endTime = System.currentTimeMillis();logger.info("请求耗时:{}ms", endTime - startTime);}// 销毁:容器关闭时执行一次@Overridepublic void destroy() {logger.info("LogFilter销毁...");}}

步骤 2:启动类添加注解

在 Spring Boot 启动类上添加@ServletComponentScan,开启 Servlet 组件扫描(否则@WebFilter不生效):
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.web.servlet.ServletComponentScan;@SpringBootApplication// 扫描Servlet组件(Filter、Servlet、Listener)@ServletComponentScanpublic class FilterDemoApplication {public static void main(String[] args) {SpringApplication.run(FilterDemoApplication.class, args);}}

测试效果

启动项目后,访问任意接口(如http://localhost:8080/hello),控制台会输出:
LogFilter初始化...请求URL:/hello,开始时间:1694567890123请求耗时:15ms

方式 2:Java 配置类(推荐,支持多过滤器排序)

当项目中有多个过滤器时,@WebFilter无法指定执行顺序(顺序由类名首字母决定),此时推荐用FilterRegistrationBean配置,手动控制过滤器顺序。

步骤 1:创建多个过滤器

新建LogFilter(日志记录)和AuthFilter(权限验证),不添加@Component@WebFilter(避免自动注册):
// 日志过滤器(同上,省略init和destroy,核心看doFilter)public class LogFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {logger.info("LogFilter:开始记录日志...");chain.doFilter(request, response);logger.info("LogFilter:日志记录结束...");}}// 权限过滤器:拦截需要登录的请求public class AuthFilter implements Filter {private static final Logger logger = LoggerFactory.getLogger(AuthFilter.class);@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {javax.servlet.http.HttpServletRequest httpRequest = (javax.servlet.http.HttpServletRequest) request;String token = httpRequest.getHeader("token");// 模拟权限验证:无token则拦截,返回401if (token == null || token.isEmpty()) {logger.warn("AuthFilter:无token,拒绝访问!");((javax.servlet.http.HttpServletResponse) response).setStatus(401);return;}// 有权限,放行logger.info("AuthFilter:token验证通过,放行请求...");chain.doFilter(request, response);}}

步骤 2:创建配置类注册过滤器

新建FilterConfig类,通过FilterRegistrationBean注册过滤器,并设置拦截路径执行顺序(order 值越小,优先级越高):
import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class FilterConfig {// 注册LogFilter@Beanpublic FilterRegistrationBean<LogFilter> logFilterRegistration() {FilterRegistrationBean<LogFilter> registrationBean = new FilterRegistrationBean<>();// 设置过滤器实例registrationBean.setFilter(new LogFilter());// 设置拦截路径:/* 拦截所有请求registrationBean.addUrlPatterns("/*");// 设置过滤器名称registrationBean.setName("logFilter");// 设置执行顺序:1(优先级高于AuthFilter)registrationBean.setOrder(1);return registrationBean;}// 注册AuthFilter@Beanpublic FilterRegistrationBean<AuthFilter> authFilterRegistration() {FilterRegistrationBean<AuthFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new AuthFilter());// 设置拦截路径:/api/* 只拦截API请求registrationBean.addUrlPatterns("/api/*");registrationBean.setName("authFilter");// 设置执行顺序:2(后于LogFilter执行)registrationBean.setOrder(2);return registrationBean;}}

测试多过滤器顺序

访问http://localhost:8080/api/user(携带空 token),控制台输出顺序如下(验证 LogFilter 先执行):
LogFilter:开始记录日志...AuthFilter:无token,拒绝访问!LogFilter:日志记录结束...

方式 3:@Component + @Order(仅适合全局拦截,不推荐)

若过滤器需要拦截所有请求(/*),可直接用@Component注入容器,配合@Order指定顺序。但这种方式无法自定义拦截路径(默认拦截所有),灵活性低,仅适合简单场景。
示例代码:
import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import javax.servlet.*;import java.io.IOException;// 注入容器,默认拦截所有请求@Component// 设置执行顺序:1(优先级高)@Order(1)public class GlobalFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {System.out.println("GlobalFilter:拦截所有请求...");chain.doFilter(request, response);}}

三、过滤器常见问题与解决方案

1. 过滤器不生效?

排查方向:
  • 启动类是否添加@ServletComponentScan(方式 1 必须);

  • 过滤器是否被正确注入容器(方式 2 需通过FilterRegistrationBean注册,避免漏加@Bean);

  • 拦截路径是否正确(如/api/*只拦截/api下的请求,不包括/hello)。

2. 多过滤器执行顺序错乱?

解决方案:
  • 避免用@WebFilter(无法指定顺序),改用FilterRegistrationBean的setOrder();

  • @Order注解仅在@Component注入时生效,且只对全局拦截的过滤器有效。

3. 如何排除特定路径不被拦截?

通过FilterRegistrationBean的addInitParameter()添加排除路径,再在过滤器中判断:
// 配置类中添加排除路径参数registrationBean.addInitParameter("excludedUrls", "/login,/register");// 过滤器doFilter方法中判断是否排除@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {String requestURI = ((javax.servlet.http.HttpServletRequest) request).getRequestURI();String excludedUrls = filterConfig.getInitParameter("excludedUrls");if (excludedUrls.contains(requestURI)) {// 排除路径,直接放行chain.doFilter(request, response);return;}// 其他逻辑...}

四、总结

本文讲解了 Spring Boot 过滤器的核心概念、3 种创建配置方式及常见问题:
  1. 简单场景:用@Component + @WebFilter + @ServletComponentScan,快速实现单过滤器;

  1. 复杂场景:用FilterRegistrationBean配置多过滤器,灵活控制拦截路径和执行顺序;

  1. 避免坑点:不推荐用@Component + @Order,因其无法自定义拦截路径。

过滤器是 Spring BootWeb 开发的基础组件,掌握它能帮你实现全局通用功能(如日志、权限),后续可结合 Spring Security、Shiro 等框架进一步深化权限控制。动手试试文中的案例,感受过滤器的实际作用吧!


分享给朋友:

“Spring Boot 过滤器入门:从概念到实战配置” 的相关文章

Python 自定义鼠标样式完全指南:从基础到实战(Tkinter/PyQt 双方案)

Python 自定义鼠标样式完全指南:从基础到实战(Tkinter/PyQt 双方案)在 Python GUI 开发中,默认鼠标样式往往难以满足个性化界面设计需求。无论是打造创意工具、游戏界面,还是品牌化桌面应用,自定义鼠标样式都能显著提升用户体验与视觉质感。本文将结合 Python 主流 GUI...

Java 自定义鼠标样式完全指南:从基础到进阶实践

在 Java 图形界面(GUI)开发中,默认鼠标样式往往难以满足个性化界面设计需求。无论是打造炫酷的游戏界面、专业的桌面应用,还是贴合品牌风格的工具软件,自定义鼠标样式都能显著提升用户体验。本文将从基础原理出发,结合 Swing 与 AWT 技术,通过实例详解 Java 自定义鼠标样式的实现方法,覆...

PHP 自定义鼠标样式完全指南:Web 场景实战(CSS 核心 + PHP 动态适配)

在 PHP 开发的 Web 应用中,自定义鼠标样式是提升界面个性化与用户体验的有效手段 —— 无论是电商平台的商品预览、创意官网的交互设计,还是后台管理系统的功能区分,合适的鼠标样式都能让操作逻辑更清晰、视觉效果更出彩。与 Java/Python 的桌面端 GUI 不同,PHP 作为服务器端语言,无...

Java 实现在线视频播放完整方案:从后端服务到前端播放

在 Web 开发中,在线视频播放是常见需求(如教育平台、视频网站、企业培训系统等)。Java 作为成熟的后端技术,能提供稳定的视频资源管理、权限控制、流式传输能力;配合前端播放器组件,可实现流畅的跨浏览器视频播放体验。本文将从技术选型、后端实现、前端集成、功能优化四个维度,手把手教你完成 Java...

PHP 链接数据库与基础增删改查(CRUD)操作详解

在 Web 开发中,PHP 与数据库的交互是动态网站的核心能力 —— 无论是用户登录注册、数据展示还是业务逻辑处理,都离不开 PHP 对数据库的增删改查操作。本文将以 MySQL 数据库(PHP 生态最常用的关系型数据库)为例,从环境准备、数据库连接、核心 CRUD 实现到安全优化,一步步...

Java 链接数据库与基础增删改查操作详解

在 Java 开发中,数据库交互是绝大多数应用的核心功能之一。无论是用户信息存储、业务数据统计还是日志记录,都需要通过 Java 程序与数据库建立连接并执行数据操作。本文将以 MySQL 数据库(最常用的关系型数据库之一)为例,从环境准备、数据库连接、基础增删改查(CRUD)操作到代码优化...