拦截器和过滤器

过滤器和拦截器

示例1.png

示例2.png

Filter(过滤器)

过滤器的配置比较简单,直接实现Filter接口即可,也可以通过@WebFilter注解实现对特定URL拦截。

可以看到Filter 接口中定义了三个方法。

  • init() :该方法在容器启动初始化过滤器时被调用,它在 Filter 的整个生命周期只会被调用一次。
    注意:这个方法必须执行成功,否则过滤器会不起作用。
  • doFilter():容器中的每一次请求都会调用该方法, FilterChain 用来调用下一个过滤器 Filter。
  • destroy(): 当容器销毁 过滤器实例时调用该方法,一般在方法中销毁或关闭资源,在过滤器 Filter 的整个生命周期也只会被调用一次
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import javax.servlet.*;

@Component
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter init");
}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("MyFilter doFilter");
// 继续传递请求
filterChain.doFilter(servletRequest, servletResponse);
}

@Override
public void destroy() {
System.out.println("MyFilter destroy");
}
}

Interceptor(拦截器)

拦截器是链式调用,一个应用中可以同时存在多个拦截器Interceptor, 一个请求也可以触发多个拦截器
,而每个拦截器的调用会依据它的声明顺序依次执行。

请求的拦截是通过HandlerInterceptor来实现,看到HandlerInterceptor接口中也定义了三个方法。

  • preHandle():这个方法将在请求处理之前进行调用。 注意:如果该方法的返回值为false ,将视为当前请求结束,不仅自身的拦截器会失效,还会导致其他的拦截器也不再执行。
  • postHandle():只有在 preHandle() 方法返回值为true 时才会执行。会在Controller 中的方法调用之后,DispatcherServlet
    返回渲染视图之前被调用。
    有意思的是:postHandle() 方法被调用的顺序跟 preHandle() 是相反的,先声明的拦截器 preHandle() 方法先执行,而postHandle()
    方法反而会后执行。
  • afterCompletion():只有在 preHandle() 方法返回值为true 时才会执行。在整个请求结束之后, DispatcherServlet 渲染了对应的视图之后执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.springframework.web.servlet.HandlerInterceptor;

@Component
public class MyInterceptor implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

System.out.println("Interceptor preHandle");
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

System.out.println("Interceptor postHandle");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

System.out.println("Interceptor afterCompletion");
}
}

配置自定义拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {

private final TokenInterceptor tokenInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/user/**")
.excludePathPatterns("/user/login", "/user/register");
}
}

运行顺序:

1
2
3
4
5
6
7
8
9
MyFilter  init
...
MyFilter doFilter
Interceptor preHandle
Controller
Interceptor postHandle
Interceptor afterCompletion
...
MyFilter destroy

执行顺序

过滤器用@Order注解控制执行顺序,通过@Order控制过滤器的级别,值越小级别越高越先执行。

1
2
3
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class MyFilter implements Filter {

拦截器默认的执行顺序,就是它的注册顺序,也可以通过Order(int)手动设置控制,值越小越先执行。

1
2
3
4
5
6
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/**").order(2);
registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/**").order(1);
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").order(3);
}

先声明的拦截器 preHandle() 方法先执行,而 postHandle() 方法反而会后执行。

另外还有一点就是 过滤器 不能够使用 Spring 容器资源,只能在 Servlet 容器(e.g. tomcat)启动时调用一次,
而 拦截器 是 Spring 提供的组件,由 Spring 来管理,因此它能使用 Spring 里的任何资源、对象,例如 Service 对象、数据源、事务管理等等,
通过 IoC 注入到 拦截器 中即可。
相比较而言,拦截器 要更灵活一些。

引用文章


拦截器和过滤器
http://example.com/2024/11/25/拦截器和过滤器/
Author
J1aHe
Posted on
November 25, 2024
Licensed under