什么是过滤器?
Filter 也称为过滤器,基于Servlet实现,过滤器的主要应用场景是对字符编码、跨域等问题进行过滤。Servlet的工作原理是拦截配置好的客户端请求,然后对Request和Response进行处理。Filter过滤器随着web应用的启动而启动,只初始化一次。
什么是拦截器?
拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行,基于AOP思想,对方法进行增强。和servlet 中的过滤器类似,都是对用户请求进行处理。
他们有什么不同?
- 拦截器是基于Java的反射机制,而过滤器是基于函数回调;
- 拦截器不依赖servlet容器,过滤器依赖servlet容器;
- 拦截器只能对Controller 请求起作用,而过滤器则可以对几乎所有的请求起作用;
- 拦截器可以访问action上下文、堆栈里的对象,过滤器不能访问;
- 在action生命周期中,拦截器可以多次被调用,过滤器只能在容器初始化时被调用一次。
在springboot中使用拦截器和过滤器
使用过滤器,有两种方式
- 实现 Filter 类,重写其 doFilter 方法,注意这个类是 javax.servlet 包下的
@Slf4j @Component public class MyFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { log.info("进入过滤器 MyFilter"); filterChain.doFilter(servletRequest, servletResponse); } }
- 注册
@Configuration public class FilterConfig { @Autowired private MyFilter myFilter; @Bean public FilterRegistrationBean injectFilterOne() { FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(myFilter); registrationBean.addUrlPatterns("/*"); registrationBean.setName("filter_one"); // 优先级 registrationBean.setOrder(1); return registrationBean; } }
- 使用
@WebFilter
注解
@Slf4j @WebFilter(filterName = "filter_two", urlPatterns = {"/*"}) public class MyFilter2 implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { log.info("进入过滤器 MyFilter2"); filterChain.doFilter(servletRequest, servletResponse); } }
- 这种方式需要在启动类上扫描
@WebFilter
注解,需要加上以下注解@ServletComponentScan(value = {"com.example.config.filter"})
使用拦截器
新建一个类实现 HandlerInterceptor 接口
@Component @Slf4j public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("进入拦截器 MyIntercept,preHandle 方法 "); return HandlerInterceptor.super.preHandle(request, response, handler); } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { log.info("进入拦截器 MyIntercept,postHandle 方法 "); HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { log.info("进入拦截器 MyIntercept,afterCompletion 方法 "); HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } }
注册
@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private MyInterceptor myInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { // 拦截器拦截路径 registry.addInterceptor(myInterceptor).addPathPatterns("/**"); } }
1. preHandle(......)方法:当url已经匹配到controller层中某个方法时,在方法执行前执行
它会决定是否放行,返回true,放行,返回false,不会执行
2. postHandle(……) 方法:url 匹配到Controller 中的某个方法,且执行完了该方法,
但是在 DispatcherServlet 视图渲染之前执行。在这个方法中有个 ModelAndView 参数,可以在此做一些修改动作。
3. afterCompletion(……) 方法:在整个请求处理完成后(包括视图渲染)执行,
做一些资源的清理工作,这个方法只有在 preHandle(……) 被成功执行后并且返回true才会被执行。
过滤器和拦截器放在一起的执行结果:
2023-05-06 23:41:48.774 INFO 15484 --- [nio-8080-exec-2] com.example.config.filter.MyFilter : 进入过滤器 MyFilter 2023-05-06 23:41:48.774 INFO 15484 --- [nio-8080-exec-2] com.example.config.filter.MyFilter2 : 进入过滤器 MyFilter2 2023-05-06 23:41:48.785 INFO 15484 --- [nio-8080-exec-2] c.e.config.interceptor.MyInterceptor : 进入拦截器 MyIntercept,preHandle 方法 2023-05-06 23:41:48.807 INFO 15484 --- [nio-8080-exec-2] c.e.config.interceptor.MyInterceptor : 进入拦截器 MyIntercept,postHandle 方法 2023-05-06 23:41:48.807 INFO 15484 --- [nio-8080-exec-2] c.e.config.interceptor.MyInterceptor : 进入拦截器 MyIntercept,afterCompletion 方法