在Spring Boot中实现过滤器有两种方式,一种是通过实现javax.servlet.Filter
接口,另一种是通过实现org.springframework.web.filter.OncePerRequestFilter
抽象类。下面分别介绍这两种方式的实现方法。
-
实现
javax.servlet.Filter
接口
首先,创建一个类并实现javax.servlet.Filter
接口,并实现其中的doFilter
方法。例如,我们创建一个LogFilter
类来记录请求日志:
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class LogFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String requestURI = httpRequest.getRequestURI();
System.out.println("请求:" + requestURI);
chain.doFilter(request, response);
}
@Override
public void destroy() {
// 销毁
}
}
然后,在Spring Boot应用程序中注册这个过滤器。在Spring Boot中,可以通过创建一个FilterRegistrationBean
对象来注册过滤器。例如,我们在MyApplication
类中注册LogFilter
:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Bean
public FilterRegistrationBean<LogFilter> logFilter() {
FilterRegistrationBean<LogFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new LogFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setName("LogFilter");
registrationBean.setOrder(1);
return registrationBean;
}
}
在上面的代码中,我们创建了一个名为logFilter
的FilterRegistrationBean
对象,并设置了要注册的过滤器LogFilter
,过滤的路径addUrlPatterns("/*")
,过滤器的名称setName("LogFilter")
和执行顺序setOrder(1)
。
2. 实现org.springframework.web.filter.OncePerRequestFilter
抽象类
另一种实现过滤器的方式是继承org.springframework.web.filter.OncePerRequestFilter
抽象类。例如,我们创建一个AuthFilter
类来实现身份认证:
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 AuthFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String authToken = authHeader.substring(7);
// TODO: 验证token,通过则放行,否则返回错误信息
filterChain.doFilter(request, response);
} else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Missing or invalid Authorization header.");
}
}
}
2.1 OncePerRequestFilter
OncePerRequestFilter
是Spring Framework中提供的一个抽象类,用于实现需要在每个请求中执行一次的过滤器。它继承了GenericFilterBean
类,并且在doFilter
方法中增加了一个判断:如果当前请求已经被过滤器处理过了,则直接放行,不再重复执行。
在Spring Boot中,我们可以通过继承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 ResponseTimeFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
long startTime = System.currentTimeMillis();
filterChain.doFilter(request, response);
long endTime = System.currentTimeMillis();
System.out.println("请求 " + request.getRequestURI() + " 的响应时间为 " + (endTime - startTime) + " 毫秒");
}
}
在上面的代码中,我们继承了OncePerRequestFilter
类,并实现了doFilterInternal
方法,在方法中记录了请求的响应时间。需要注意的是,doFilterInternal
方法中必须调用filterChain.doFilter
方法来继续执行后续的过滤器或请求处理程序。
要在Spring Boot中注册这个过滤器,可以在@Configuration
类中使用FilterRegistrationBean
对象,像这样:
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<ResponseTimeFilter> responseTimeFilter() {
FilterRegistrationBean<ResponseTimeFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new ResponseTimeFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setName("ResponseTimeFilter");
registrationBean.setOrder(1);
return registrationBean;
}
}