SpringBoot中过滤器Filter怎么用

发布时间:2021-09-08 15:21:03 作者:小新
来源:亿速云 阅读:204
# SpringBoot中过滤器Filter怎么用

## 一、过滤器(Filter)基础概念

### 1.1 什么是过滤器

过滤器(Filter)是Java Web开发中的核心组件之一,它可以在请求到达Servlet之前或响应返回客户端之前对HTTP请求和响应进行预处理和后处理。过滤器就像一个"筛子",能够对Web应用中的请求和响应进行过滤操作。

在Spring Boot中,过滤器依然扮演着重要角色,尽管Spring提供了更高级的拦截器(Interceptor)机制,但过滤器在以下场景中仍不可替代:

1. 与Servlet容器紧密相关的功能(如编码设置)
2. 需要处理静态资源的场景
3. 在Spring上下文之外进行的处理

### 1.2 过滤器的工作原理

过滤器基于责任链模式工作,多个过滤器可以形成一个过滤链(FilterChain)。当一个请求到达时,过滤器的执行流程如下:

客户端请求 → 过滤器1 → 过滤器2 → … → Servlet → 过滤器2 → 过滤器1 → 客户端响应


关键特点:
- 先配置的过滤器先执行(请求阶段)
- 后配置的过滤器后执行(响应阶段)
- 可以通过FilterChain控制是否继续执行下一个过滤器

### 1.3 过滤器与拦截器的区别

| 特性        | 过滤器(Filter)          | 拦截器(Interceptor)     |
|------------|------------------------|------------------------|
| 作用范围    | Servlet容器级别         | Spring MVC上下文级别    |
| 依赖关系    | 不依赖Spring框架        | 依赖Spring MVC框架      |
| 实现方式    | 实现javax.servlet.Filter| 实现HandlerInterceptor  |
| 执行时机    | 更早(进入Servlet前)     | 稍晚(进入Controller前)  |
| 使用场景    | 编码转换、跨域处理等     | 权限校验、日志记录等     |

## 二、Spring Boot中过滤器的基本使用

### 2.1 创建基础过滤器

在Spring Boot中创建一个过滤器非常简单,只需要实现`javax.servlet.Filter`接口:

```java
import javax.servlet.*;
import java.io.IOException;

public class BasicFilter implements Filter {
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化方法
        System.out.println("BasicFilter初始化...");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        System.out.println("BasicFilter 前置处理");
        // 执行后续过滤器或Servlet
        chain.doFilter(request, response);
        System.out.println("BasicFilter 后置处理");
    }

    @Override
    public void destroy() {
        // 销毁方法
        System.out.println("BasicFilter销毁...");
    }
}

2.2 注册过滤器

在Spring Boot中有多种方式注册过滤器,以下是三种常见方式:

方式1:使用@WebFilter注解 + @ServletComponentScan

@WebFilter(urlPatterns = "/*")
public class AnnotationFilter implements Filter {
    // 过滤器实现
}

// 在启动类上添加扫描注解
@ServletComponentScan
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

方式2:通过FilterRegistrationBean注册

@Configuration
public class FilterConfig {
    
    @Bean
    public FilterRegistrationBean<BasicFilter> registerBasicFilter() {
        FilterRegistrationBean<BasicFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new BasicFilter());
        registration.addUrlPatterns("/*");
        registration.setOrder(1); // 设置过滤器顺序
        registration.setName("basicFilter");
        return registration;
    }
}

方式3:使用@Component自动注册(不推荐)

@Component
public class ComponentFilter implements Filter {
    // 过滤器实现
}

注意:使用@Component注册的过滤器无法自定义URL模式,会默认过滤所有请求,且顺序难以控制。

2.3 过滤器执行顺序控制

当应用中有多个过滤器时,执行顺序非常重要。在Spring Boot中控制过滤器顺序的方式:

  1. @WebFilter方式:通过实现javax.servlet.annotation.WebFilterfilterName属性按字母顺序执行
  2. FilterRegistrationBean方式:通过setOrder()方法设置顺序值,值越小优先级越高
  3. @Order注解:对@Component过滤器有效,但无法控制URL模式

最佳实践是使用FilterRegistrationBean,因为它提供了最灵活的控制:

@Configuration
public class FilterConfig {
    
    @Bean
    public FilterRegistrationBean<FirstFilter> firstFilter() {
        FilterRegistrationBean<FirstFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new FirstFilter());
        bean.addUrlPatterns("/*");
        bean.setOrder(1); // 第一个执行
        return bean;
    }
    
    @Bean
    public FilterRegistrationBean<SecondFilter> secondFilter() {
        FilterRegistrationBean<SecondFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new SecondFilter());
        bean.addUrlPatterns("/*");
        bean.setOrder(2); // 第二个执行
        return bean;
    }
}

三、过滤器的核心应用场景

3.1 请求日志记录

public class LoggingFilter implements Filter {
    
    private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        long startTime = System.currentTimeMillis();
        
        // 记录请求信息
        logger.info("请求开始: {} {}, 参数: {}", 
                   req.getMethod(), 
                   req.getRequestURI(),
                   getRequestParams(req));
        
        chain.doFilter(request, response);
        
        long duration = System.currentTimeMillis() - startTime;
        logger.info("请求完成: 耗时{}ms", duration);
    }
    
    private String getRequestParams(HttpServletRequest req) {
        return req.getParameterMap().entrySet().stream()
                .map(entry -> entry.getKey() + "=" + Arrays.toString(entry.getValue()))
                .collect(Collectors.joining(", "));
    }
}

3.2 认证与授权检查

public class AuthFilter implements Filter {
    
    private static final List<String> WHITE_LIST = Arrays.asList("/login", "/public");

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        
        // 白名单检查
        if (WHITE_LIST.contains(req.getRequestURI())) {
            chain.doFilter(request, response);
            return;
        }
        
        // 检查认证token
        String token = req.getHeader("Authorization");
        if (!validateToken(token)) {
            res.sendError(HttpServletResponse.SC_UNAUTHORIZED, "无效的认证信息");
            return;
        }
        
        chain.doFilter(request, response);
    }
    
    private boolean validateToken(String token) {
        // 实际项目中应实现完整的token验证逻辑
        return token != null && token.startsWith("Bearer ");
    }
}

3.3 跨域处理(CORS)

虽然Spring Boot提供了@CrossOrigin注解和全局CORS配置,但有时仍需要使用过滤器处理:

public class CorsFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        HttpServletResponse res = (HttpServletResponse) response;
        
        res.setHeader("Access-Control-Allow-Origin", "*");
        res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        res.setHeader("Access-Control-Max-Age", "3600");
        res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
        
        if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) request).getMethod())) {
            res.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(request, response);
        }
    }
}

3.4 请求参数处理

统一字符编码

public class EncodingFilter implements Filter {
    
    private String encoding = "UTF-8";

    @Override
    public void init(FilterConfig filterConfig) {
        String encodingParam = filterConfig.getInitParameter("encoding");
        if (encodingParam != null) {
            encoding = encodingParam;
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding(encoding);
        response.setCharacterEncoding(encoding);
        chain.doFilter(request, response);
    }
}

XSS防护

public class XssFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        chain.doFilter(new XssRequestWrapper((HttpServletRequest) request), response);
    }
    
    private static class XssRequestWrapper extends HttpServletRequestWrapper {
        // 实现XSS防护逻辑
    }
}

四、高级过滤器应用技巧

4.1 过滤器异常处理

public class ExceptionHandlingFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } catch (BusinessException e) {
            handleBusinessException((HttpServletResponse) response, e);
        } catch (Exception e) {
            handleUnexpectedException((HttpServletResponse) response, e);
        }
    }
    
    private void handleBusinessException(HttpServletResponse response, 
                                        BusinessException e) throws IOException {
        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
        response.getWriter().write("{\"error\":\"" + e.getMessage() + "\"}");
        response.getWriter().flush();
    }
    
    private void handleUnexpectedException(HttpServletResponse response, 
                                          Exception e) throws IOException {
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        response.getWriter().write("{\"error\":\"系统异常\"}");
        response.getWriter().flush();
    }
}

4.2 性能监控过滤器

public class MetricsFilter implements Filter {
    
    private final MetricRegistry metricRegistry;

    public MetricsFilter(MetricRegistry metricRegistry) {
        this.metricRegistry = metricRegistry;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String metricName = "request." + req.getMethod() + "." + req.getRequestURI()
                .replaceAll("/", ".");
        
        Timer.Context timerContext = metricRegistry.timer(metricName).time();
        try {
            chain.doFilter(request, response);
        } finally {
            timerContext.stop();
        }
    }
}

4.3 请求/响应内容修改

public class ContentModificationFilter implements Filter {
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        ContentCachingResponseWrapper responseWrapper = 
            new ContentCachingResponseWrapper((HttpServletResponse) response);
        
        chain.doFilter(request, responseWrapper);
        
        byte[] content = responseWrapper.getContentAsByteArray();
        if (content.length > 0) {
            String contentStr = new String(content, response.getCharacterEncoding());
            // 修改响应内容
            String modifiedContent = contentStr.replace("old", "new");
            responseWrapper.resetBuffer();
            responseWrapper.getWriter().write(modifiedContent);
        }
        responseWrapper.copyBodyToResponse();
    }
}

4.4 与Spring Security集成

当同时使用过滤器和Spring Security时,需要注意执行顺序:

@Configuration
public class SecurityFilterConfig {
    
    @Bean
    public FilterRegistrationBean<CustomSecurityFilter> securityFilterRegistration() {
        FilterRegistrationBean<CustomSecurityFilter> registration = 
            new FilterRegistrationBean<>();
        registration.setFilter(new CustomSecurityFilter());
        registration.addUrlPatterns("/*");
        registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); // 在Spring Security之前执行
        return registration;
    }
}

五、常见问题与最佳实践

5.1 常见问题排查

问题1:过滤器不生效

问题2:过滤器执行顺序不符合预期

问题3:性能问题

5.2 性能优化建议

  1. 减少过滤器数量:合并功能相似的过滤器
  2. 使用条件过滤:对静态资源跳过某些过滤器
  3. 异步处理:对于耗时操作考虑使用异步过滤器
  4. 缓存策略:在过滤器中合理使用缓存
public class CacheFilter implements Filter {
    
    private CacheManager cacheManager;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String cacheKey = generateCacheKey(req);
        
        // 检查缓存
        if (cacheManager.get(cacheKey) != null) {
            writeCachedResponse(response, cacheManager.get(cacheKey));
            return;
        }
        
        // 缓存响应
        ContentCachingResponseWrapper responseWrapper = 
            new ContentCachingResponseWrapper((HttpServletResponse) response);
        chain.doFilter(request, responseWrapper);
        
        byte[] responseData = responseWrapper.getContentAsByteArray();
        cacheManager.put(cacheKey, responseData);
        responseWrapper.copyBodyToResponse();
    }
}

5.3 测试策略

单元测试

public class AuthFilterTest {
    
    @Test
    public void testWhiteListAccess() throws Exception {
        AuthFilter filter = new AuthFilter();
        MockHttpServletRequest request = new MockHttpServletRequest();
        MockHttpServletResponse response = new MockHttpServletResponse();
        FilterChain chain = mock(FilterChain.class);
        
        request.setRequestURI("/login");
        filter.doFilter(request, response, chain);
        
        verify(chain).doFilter(request, response);
    }
}

集成测试

@SpringBootTest
@AutoConfigureMockMvc
public class FilterIntegrationTest {
    
    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testAuthFilterWithValidToken() throws Exception {
        mockMvc.perform(get("/api/resource")
                .header("Authorization", "Bearer valid-token"))
                .andExpect(status().isOk());
    }
    
    @Test
    public void testAuthFilterWithoutToken() throws Exception {
        mockMvc.perform(get("/api/resource"))
                .andExpect(status().isUnauthorized());
    }
}

六、实际案例:构建API网关过滤器

6.1 需求分析

假设我们需要实现一个API网关过滤器,需要处理以下功能: 1. 请求认证 2. 限流控制 3. 请求/响应日志 4. 耗时统计

6.2 实现代码

public class ApiGatewayFilter implements Filter {
    
    private final RateLimiter rateLimiter;
    private final Logger logger = LoggerFactory.getLogger(getClass());

    public ApiGatewayFilter(RateLimiter rateLimiter) {
        this.rateLimiter = rateLimiter;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        
        // 1. 认证检查
        if (!authenticate(req)) {
            sendError(res, HttpServletResponse.SC_UNAUTHORIZED, "认证失败");
            return;
        }
        
        // 2. 限流检查
        if (!rateLimiter.tryAcquire()) {
            sendError(res, HttpServletResponse.SC_TOO_MANY_REQUESTS, "请求过于频繁");
            return;
        }
        
        // 3. 记录请求日志
        long startTime = System.currentTimeMillis();
        logRequest(req);
        
        // 4. 处理请求
        ContentCachingResponseWrapper responseWrapper = 
            new ContentCachingResponseWrapper(res);
        try {
            chain.doFilter(request, responseWrapper);
        } finally {
            // 5. 记录响应日志和耗时
            long duration = System.currentTimeMillis() - startTime;
            logResponse(req, responseWrapper, duration);
            responseWrapper.copyBodyToResponse();
        }
    }
    
    // 其他辅助方法...
}

6.3 配置与使用

@Configuration
public class ApiGatewayConfig {
    
    @Bean
    public FilterRegistrationBean<ApiGatewayFilter> apiGatewayFilter() {
        FilterRegistrationBean<ApiGatewayFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new ApiGatewayFilter(new RedisRateLimiter()));
        bean.addUrlPatterns("/api/*");
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        bean.setName("apiGatewayFilter");
        return bean;
    }
}

七、总结与展望

7.1 关键点回顾

  1. 过滤器基础:理解过滤器的生命周期和工作原理
  2. 注册方式:掌握@WebFilter、FilterRegistrationBean等注册方式及适用场景
  3. 执行顺序:熟练控制多个过滤器的执行顺序
  4. 应用场景:灵活运用过滤器解决实际问题

7.2 发展趋势

随着技术的演进,过滤器在以下方面有新的发展: 1. 云原生适配:与Service Mesh集成

推荐阅读:
  1. Java中Filter过滤器的使用
  2. angularjs中的filter(过滤器)

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

springboot filter

上一篇:tp5更新字段的方式

下一篇:python线程通信Condition的实例用法介绍

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》