您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# 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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。