本文最后更新于 927 天前,其中的信息可能已经有所发展或是发生改变。
过滤器 (Filter)
过滤器基于函数回调实现,属于Servlet规范,导致它只能在Web程序使用。
- 在Application上声明@ServletComponentScan注解
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; //@ServletComponentScan能够识别当前包及其子包下的@WebFilter注解 @ServletComponentScan @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } - 自定义过滤器
import lombok.extern.slf4j.Slf4j; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.annotation.WebInitParam; import java.io.IOException; @Slf4j @WebFilter(urlPatterns = "/custom/*",//*表示通配符,此处即可拦截/custom/user,也可拦截/custom/user/me等多级URL filterName = "customFilter", initParams = { @WebInitParam(name = "user", value = "admin") }) //此处无需使用@Component public class CustomFilter implements Filter { //Web容器中的每一次请求都会调用该方法 @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { log.info("过滤前执行"); filterChain.doFilter(servletRequest, servletResponse);//交由后续过滤器调用,若当前过滤器是过滤器链中最后一个,则将请求交由Controller。也可给客户端直接返回响应信息。 log.info("过滤后执行"); } //Web容器初始化过滤器时调用,只会被调用一次 @Override public void init(FilterConfig filterConfig) throws ServletException { //通过FilterConfig可以获取web.xml文件中的初始化参数 String filterName = filterConfig.getFilterName();//来自@WebFilter的filterName,此处为customFilter log.info(filterName); String user = filterConfig.getInitParameter("user");//来自@WebInitParam的name,此处为admin log.info(user); ServletContext servletContext = filterConfig.getServletContext(); } //Web容器销毁过滤器实例时调用,只会被调用一次 @Override public void destroy() { log.info("destroy"); } } - 更改过滤器执行顺序
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; @Configuration public class GlobalMvcConfig { @Bean public FilterRegistrationBeanfilterRegistrationBean() { FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new CustomFilter());//此处的Filter不必使用@WebFilter registrationBean.addUrlPatterns("/material/*");//类似@WebFilter的urlPatterns registrationBean.setName("customFilter");//类似@WebFilter的filterName registrationBean.addInitParameter("user", "admin");//类似@WebInitParam registrationBean.setOrder(1);//Filter默认根据filterName顺序执行,setOrder方法可以更改doFilter执行顺序 return registrationBean; } //多个Filter需要声明多个FilterRegistrationBean @Bean public FilterRegistrationBean filterRegistrationBean2() { //TODO } }
拦截器 (Interceptor)
拦截器基于动态代理实现,属于Spring容器管理,可以单独使用。
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CustomInterceptor implements HandlerInterceptor {
//在Controller方法调用之前执行
//注意:如果该方法的返回值为false,表示终止当前请求,不仅自身拦截失效,还会导致后续拦截器也不再执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return false;
}
//在Controller方法调用之后,DispatcherServlet返回渲染视图之前执行
//注意:只有在preHandle方法返回true时才会生效
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
//在DispatcherServlet返回渲染视图之后执行
//注意:只有在preHandle方法返回true时才会生效
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
注意:拦截器是在SpringContext之前加载的,所以不能在拦截器中直接使用Spring容器管理的Bean,解决办法如下:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
public class GlobalMvcConfig implements WebMvcConfigurer {
@Bean
public CustomInterceptor customInterceptor() {
return new CustomInterceptor();
}
//定义好的拦截器可以通过addPathPatterns、excludePathPatterns等方法设置需要拦截或排除的URL
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(customInterceptor())
.addPathPatterns("/oauth/token")
.order(0)//Interceptor默认根据addInterceptor添加顺序执行,order方法可以更改执行顺序
.excludePathPatterns("/oauth/check_token");
}
}
@Order & Ordered接口
注意:@Order注解和Ordered接口并不能改变过滤器和拦截器的执行顺序,详情请参考《Spring Boot 常用注解》。
触发时机
Tomcat → Filter → Servlet → Interceptor → Controller