十四、Spring Web 过滤器使用常见错误(下)(没事别用@WebFilter,问题一堆)
一.@WebFilter 过滤器使用 @Order 无效
1、代码分析
1.主启动类:使用了@ServletComponentScan
@SpringBootApplication
@ServletComponentScan
@Slf4j
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
log.info("启动成功");
}
}
2.Controller
@Controller
@Slf4j
public class StudentController {
@PostMapping("/regStudent/{name)}")
@ResponseBody
public String saveUser(String name) throws Exception {
System.out.println("......用户注册成功");
return "success";
}
}
3.Filter:AuthFilter权限认证
@WebFilter
@Slf4j
@Order(2)
public class AuthFilter implements Filter {
@SneakyThrows
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
if(isPassAuth()){
System.out.println("通过授权");
chain.doFilter(request, response);
}else{
System.out.println("未通过授权");
((HttpServletResponse)response).sendError(401);
}
}
private boolean isPassAuth() throws InterruptedException {
System.out.println("执行检查权限");
Thread.sleep(1000);
return true;
}
}
4.Filter:TimeCostFilter耗时
@WebFilter
@Slf4j
@Order(1)
public class TimeCostFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("#开始计算接口耗时");
long start = System.currentTimeMillis();
chain.doFilter(request, response);
long end = System.currentTimeMillis();
long time = end - start;
System.out.println("#执行时间(ms):" + time);
}
}
2、案例解析
上面代码中,使用了@Order,期望按顺序执行,但是实际并非如此。
主要原因就是@WebFilter构建的并非是普通的Bean对象,不会根据Order的值去设置order属性。
3、问题修正
不使用@WebFilter,实现FilterRegistrationBean来配置普通的Bean
@Configuration
public class FilterConfiguration {
@Bean
public FilterRegistrationBean authFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new AuthFilter());
registration.addUrlPatterns("/*");
registration.setOrder(2);
return registration;
}
@Bean
public FilterRegistrationBean timeCostFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new TimeCostFilter());
registration.addUrlPatterns("/*");
registration.setOrder(1);
return registration;
}
}
二.过滤器被多次执行
1、代码分析
@WebFilter
@Slf4j
@Order(2)
@Component
public class AuthFilter implements Filter {
@SneakyThrows
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain){
if(isPassAuth()){
System.out.println("通过授权");
chain.doFilter(request, response);
}else{
System.out.println("未通过授权");
((HttpServletResponse)response).sendError(401);
}
}
private boolean isPassAuth() throws InterruptedException {
System.out.println("执行检查权限");
Thread.sleep(1000);
return true;
}
}
此处代码的关键在于同时使用了@Component和@WebFilter,会生成两种不同的Bean对象。导致Filter被执行了两遍。
2、案例解析
任何通过 @Component 修饰的的类,都可以自动注册到 Spring,且能被 Spring 直接实例化。
3、问题修正
@Component和@WebFilter不能同时使用
@Slf4j
@Order(1)
@Component
public class TimeCostFilter implements Filter {
//省略非关键代码
}