拦截器和过滤器
什么是过滤器?
过滤器是以链的形式在容器中处理的,这意味着它们可以在请求达到servlet之前对其进行访问,也可以在响应返回客户端之前对其进行拦截,这种访问使得过滤器可以检查并修改请求和响应的内容。
什么是拦截器?
拦截器是AOP的一种实现策略,用于在某个方法或字段被访问前对它进行拦截,然后在其之前或之后加上某些操作,同样,Interceptor也是链式调用,每个interceptor的调用会依据它声明顺序依次执行。
过滤器中的接口方法
- init():在Servlet容器创建过滤器实例的时候调用,以确保过滤器能够正常工作,承担初始化工作;
- doFilter():核心方法,用于对每个拦截到的请求做好一些设定的操作;
- destoy(): Filter的销毁,在Servlet容器销毁过滤器实例时调用,释放其占用资源,只有当doFilter方法中的所有线程都退出或超时候,才会被执行;
如何适应过滤器
@Component
@Order(1) // 过滤顺序,值越小越先执行
@WebFilter(urlPatterns = "/demoFilter", filterName = "filterTest")
public class DemoFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("filter初始化中...");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("\ndoFilter()开始执行:发往 " + ((HttpServletRequest) servletRequest).getRequestURL().toString() + " 的请求已被拦截");
System.out.println("检验接口是否被调用,尝试获取contentType如下: " + servletResponse.getContentType());
// filter的链式调用;将请求转给下一条过滤链
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("检验接口是否被调用,尝试获取contentType如下: " + servletResponse.getContentType());
System.out.println("doFilter()执行结束。\n");
}
@Override
public void destroy() {
System.out.println("filter销毁中...");
}
}
@WebFilter
用于将类声明为过滤器;
@WebFilter
的常用属性
属性名 | 类型 | 描述 |
| String | 指定过滤器的name属性,等同于 |
| String[] | 该属性等价于 |
| String[] | 指定一组过滤器的URL匹配模式,等价于 |
| String[] | 指定过滤器将应用于哪些Servlet,取值是 |
| DispatcherType | 指定过滤器的转发模式,取值包括ASYNC、ERROR、FORWARD、INCLUCE、REQUEST |
| WebInitParam[] | 指定一组过滤器初始化参数,等价于 |
| boolean | 声明过滤器是否支持异步操作模式,等价于 |
| String | 该过滤器的描述信息 |
| String | 该过滤器的显示名,通常配合工具使用 |
拦截器的接口方法
- preHandler():方法的前置处理,将在请求处理之前被调用,一般用来对方法进行一些前置初始化操作,或是对当前请求做一些预处理,此外还可以用来进行权限校验之类的判断,来决定请求是否要继续进行下去。
该方法返回一个布尔值,若该值为false,则请求结束,后续的Interceptor和Controller都不会再执行,若该值为true,则会继续调用下一个Interceptor的preHandler方法,如果已经达到最后一个Interceptor,就会调用当前请求的Controller。 - postHandler():方法的后置处理,将在请求处理之后被调用,虽然在Controller方法调用后再执行,但它的调用依然在DispatcherServlet进行试图渲染并返回之前,所以一般可以通过它对Controller处理之后的ModelAndView对象进行操作。
- afterCompletion():在整个请求处理完成后执行,主要用来进行一些资源的清理工作。
如何自定义拦截器
- 自定义拦截器
@Component
public class DemoInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("afterHandle");
}
}
- 注册拦截器
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 如果有多个拦截器,继续registry.add往下添加就可以啦
registry.addInterceptor(new DemoInterceptor()).addPathPatterns("/demoInterceptor/**");
}
}
InterceptorRegistry拦截器注册类方法
addInterceptor
:添加拦截器;addPathPatterns
:指定添加的拦截器应用于哪些URL;excludePathPatterns
:指定添加的拦截器不应用于哪些URL;
拦截器和过滤器的区别
Spring的拦截器与Servlet的Filter有相似之处,比如二者都是AOP编程思想的体现,都能实现权限检查、日志记录等。不同的是:
使用范围不同:Filter是Servlet规范规定的,只能用于Web程序中。而拦截器既可以用于Web程序,也可以用于Application、Swing程序中。 规范不同:Filter是在Servlet规范中定义的,是Servlet容器支持的。而拦截器是在Spring容器内的,是Spring框架支持的。 使用的资源不同:同其他的代码块一样,拦截器也是一个Spring的组件,归Spring管理,配置在Spring文件中,因此能使用Spring里的任何资源、对象,例如Service对象、数据源、事务管理等,通过IoC注入到拦截器即可;而Filter则不能。
深度不同:Filter在只在Servlet前后起作用。而拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。所以在Spring构架的程序中,要优先使用拦截器。 实际上Filter和Servlet极其相似,区别只是Filter不能直接对用户生成响应。实际上Filter里doFilter()方法里的代码就是从多个Servlet的service()方法里抽取的通用代码,通过使用Filter可以实现更好的复用。 filter是一个可以复用的代码片段,可以用来转换HTTP请求、响应和头信息。Filter不像Servlet,它不能产生一个请求或者响 应,它只是修改对某一资源的请求,或者修改从某一的响应。 JSR中说明的是,按照多个匹配的Filter,是按照其在web.xml中配置的顺序 来执行的。 所以这也就是,把自己的Filter或者其他的Filter(比如UrlRewrite的Filter)放在Struts的 DispatcherFilter的前面的原因。因为,它们需要在请求被Struts2框架处理之前,做一些前置的工作。 当Filter被调用,并且进入了Struts2的DispatcherFilter中 后,Struts2会按照在Action中配置的Interceptor Stack中的Interceptor的顺序,来调用Interceptor。