小秦哥 发表于 2025-1-7 17:41:08

Spring Boot 框架下的过滤器

1. 过滤器的基础概念

1.1 什么是过滤器?



[*]Servlet 规范的一部门,定义在 javax.servlet.Filter 接口中。
[*]在 HTTP 请求到达目标资源(如 Controller)之前或相应返回客户端之前,拦截并对其进行预处理或后处理。
1.2 过滤器的焦点方法

javax.servlet.Filter 接口定义了以下三个方法:


[*] init(FilterConfig filterConfig)

[*]在过滤器初始化时调用,通常用于加载资源或初始化设置。

[*] doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

[*]焦点方法,用于拦截和处理请求或相应。
[*]调用 chain.doFilter(request, response) 体现将请求传递给下一个过滤器或目标资源。

[*] destroy()

[*]在过滤器烧毁时调用,用于释放资源。

2. Spring Boot 项目中如何使用过滤器

在 Spring Boot 中,可以通过以下两种方式注册过滤器:
2.1 自动注册过滤器

通过 @Component 注解将过滤器注册为 Spring Bean,Spring Boot 会自动加载并将其添加到过滤器链中。
示例代码:
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Component
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) {
      System.out.println("过滤器初始化");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
      HttpServletRequest httpRequest = (HttpServletRequest) request;
      System.out.println("请求路径:" + httpRequest.getRequestURI());
      chain.doFilter(request, response); // 继续传递请求
    }

    @Override
    public void destroy() {
      System.out.println("过滤器销毁");
    }
}
解释:


[*]@Component:

[*]将该类注册为 Spring Bean,Spring Boot 自动将其作为过滤器加载。
[*]默认拦截所有请求(/*)。

[*]doFilter 方法:

[*]HttpServletRequest 用于获取请求的详细信息(如路径、参数)。
[*]chain.doFilter 体现继续将请求传递给下一个过滤器或目标资源。

2.2 手动注册过滤器

通过 FilterRegistrationBean 手动注册过滤器,可以指定 URL 匹配规则和执行顺序。
示例代码:
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<MyFilter> registerMyFilter() {
      FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
      registrationBean.setFilter(new MyFilter()); // 注册过滤器
      registrationBean.addUrlPatterns("/api/*");// 仅拦截 /api/ 开头的请求
      registrationBean.setOrder(1);
            // 设置执行顺序,值越小优先级越高
      return registrationBean;
    }
}
解释:


[*]FilterRegistrationBean:

[*]用于手动注册过滤器,提供灵活的设置选项。

[*]addUrlPatterns:

[*]定义过滤器的作用范围,好比这里仅拦截 /api/* 的请求。

[*]setOrder:

[*]定义过滤器的执行顺序,值越小优先级越高。

3. 使用 Spring 提供的扩展过滤器

Spring 提供了一个扩展类 OncePerRequestFilter,它是对标准过滤器的加强,用于确保在一次请求中只执行一次过滤逻辑(防止重复过滤)。
示例代码:
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyOncePerRequestFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
      System.out.println("请求路径:" + request.getRequestURI());
      filterChain.doFilter(request, response); // 继续传递请求
    }
}
注册方式: 可以通过 @Component 或 FilterRegistrationBean 注册,方式与标准过滤器一致。
解释:


[*]OncePerRequestFilter:

[*]确保在一次请求中只执行一次过滤器逻辑。

[*]doFilterInternal:

[*]处理请求的焦点方法,逻辑和标准 Filter 的 doFilter 类似。

4. 过滤器的执行顺序 

在 Spring Boot 中,多个过滤器的执行顺序由以下规则决定: 
4.1 自动注册的过滤器:

示例:
@Component
@Order(1) // 优先级最高
public class FirstFilter implements Filter {
    ...
}

@Component
@Order(2) // 优先级次之
public class SecondFilter implements Filter {
    ...
}


[*]默认按加载顺序执行。
[*]可以通过 @Order 注解设置优先级(值越小优先级越高)。
4.2 手动注册的过滤器:

示例:
registrationBean.setOrder(1);


[*]使用 FilterRegistrationBean#setOrder 方法设置优先级。
5. 常见过滤器应用场景



[*] 用户认证和授权

[*]检查请求头中是否携带有效的 Token。
[*]验证用户权限。

[*] 请求日志记录
示例:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    System.out.println("请求路径:" + httpRequest.getRequestURI());
    chain.doFilter(request, response);
}


[*]记录请求的详细信息(如路径、IP 地址、参数)。

[*] 跨域处理
示例:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    HttpServletResponse httpResponse = (HttpServletResponse) response;
    httpResponse.setHeader("Access-Control-Allow-Origin", "*");
    httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
    chain.doFilter(request, response);
}


[*]在相应头中添加跨域支持信息。

[*] 加解密

[*]对请求体进行解密,对相应体进行加密。

6. 注意事项



[*] 避免业务逻辑的复杂化:

[*]过滤器应专注于全局性逻辑(如日志、认证),复杂的业务逻辑应放在 Service 层处理。

[*] 避免重复过滤:

[*]使用 OncePerRequestFilter 防止在同一个请求中多次执行过滤器逻辑。

[*] 路径匹配规则:

[*]通过 addUrlPatterns 或在 doFilter 中手动判定,确保过滤器只作用于必要的路径。

[*] 资源拦截控制:

[*]清除静态资源(如 .css, .js)的拦截,避免对静态资源应用不必要的逻辑。

7.一个请求在整个Spring Boot Web 应用中的处理流程

以一个常见的 Spring Boot Web 应用为例,处理一个请求大概会经过多个环节:
[客户端请求]
   ↓
// 过滤器链
   ↓
// DispatcherServlet
   ↓
// 可选
   ↓

   ↓
[视图解析或返回响应]
   ↑
// 响应回程,也可以在过滤器里做后置处理
   ↑
[客户端接收响应]


[*]过滤器链先于 Spring MVC 的拦截器执行。
[*]在 Filter.doFilter 中,假如调用 chain.doFilter(request, response),请求才会进入下一个过滤器或目标 Servlet。
[*]相应返回时,也会逆向经过过滤器链,为我们提供后置处理的时机。
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Spring Boot 框架下的过滤器