# 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销毁..."); } }
在Spring Boot中有多种方式注册过滤器,以下是三种常见方式:
@WebFilter(urlPatterns = "/*") public class AnnotationFilter implements Filter { // 过滤器实现 } // 在启动类上添加扫描注解 @ServletComponentScan @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
@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; } }
@Component public class ComponentFilter implements Filter { // 过滤器实现 }
注意:使用@Component注册的过滤器无法自定义URL模式,会默认过滤所有请求,且顺序难以控制。
当应用中有多个过滤器时,执行顺序非常重要。在Spring Boot中控制过滤器顺序的方式:
javax.servlet.annotation.WebFilter
的filterName
属性按字母顺序执行setOrder()
方法设置顺序值,值越小优先级越高最佳实践是使用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; } }
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(", ")); } }
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 "); } }
虽然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); } } }
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); } }
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防护逻辑 } }
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(); } }
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(); } } }
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(); } }
当同时使用过滤器和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; } }
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(); } }
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网关过滤器,需要处理以下功能: 1. 请求认证 2. 限流控制 3. 请求/响应日志 4. 耗时统计
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(); } } // 其他辅助方法... }
@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; } }
随着技术的演进,过滤器在以下方面有新的发展: 1. 云原生适配:与Service Mesh集成
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。