Interceptor
拦截器
拦截器概述
HandlerInterceptor
接口,该接口提供了拦截器的功能,如果自定义拦截器就要实现该接口
,HandlerInterceptor
源码如下
public interface HandlerInterceptor {
// 该方法会在控制器方法前执行
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
// 该方法会在控制器方法调用之后,且解析视图之前执行
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
// 该方法会在整个请求完成,即视图渲染结束之后执行
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
}
Interceptor
依赖于 web
框架,我们经常在 springMVC
中用到该配置,在这个场景下 Interceptor
就依赖于 springMVC
框架。Interceptor
基于 Java
的反射机制,属于AOP
的一种运用
- 由于拦截器是基于
web
框架的调用,因此可以使用spring
的依赖注入进行一些业务操作,同时一个拦截器实例在一个controller
生命周期之内可以多次调用 - 只能对
controller
请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理
拦截器中方法的执行流程
- 请求到达
DispatcherServlet
,DispatcherServlet
发送至Interceptor
,执行preHandle()
方法,该方法会返回一个布尔值。如果为false
,则结束所有流程:如果为true
, 则执行下一步 - 请求达到
controller
,执行处理器逻辑,它包含控制器的功能 - 执行
postHandle()
方法 - 执行视图解析和视图渲染
- 执行
afterCompletion()
方法
拦截器的配置
传统项目拦截器的配置
基于 springMVC
的项目 ,我们之前的案例配置拦截器的方式如下
springboot
项目拦截器的配置
实现 HandlerInterceptor
接口编写拦截器
继承 HandlerInterceptorAdapter
也可以,它是 HandlerInterceptor
的子类
public class MyInterceptor implements HandlerInterceptor {
// preHandle在执行Controller之前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("MyInterceptor-处理器执行前方法preHandle,返回true则不拦截后续的处理");
return true;
}
// postHandle在请求执行完之后 渲染ModelAndView返回之前执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
System.out.println("MyInterceptor-处理器处理后方法postHandle");
}
// afterCompletion在整个请求执行完毕后执行,无论是否发生异常都会执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
System.out.println("MyInterceptor-处理器完成后方法afterCompletion");
}
}
实现 WebMvcConfigurer
接口注册拦截器
先说明下几个可以用来注册拦截器的类和接口
WebMvcConfigurerAdapter
:springboot 2.0
以后的版本已失效WebMvcConfigurationSupport
: 不需要返回逻辑视图,可以选择继承此类WebMvcConfigurer
:返回逻辑视图,可以选择实现此方法,重写addInterceptor()
方法
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册拦截器到 springMVC 机制, 然后它会返回一个拦截器注册
InterceptorRegistration regist = registry.addInterceptor(new MyInterceptor());
// 指定拦截匹配模式,限制拦截器拦截请求
regist.addPathPatterns("/artisan/interceptor/*");
// 不拦截的路径
regist.excludePathPatterns("/artisan/interceptor/exclude/*");
}
}
多个拦截器的执行顺序
使用的是责任链模式的规则:对于 preHandle()
采用 先注册先执行
,而 postHandle()
和 afterCompletion()
则是 先注册后执行
Filter
过滤器
过滤器概述
过滤器 Filter
,是在 Servlet
规范中定义的,是 Servlet
容器支持的,该接口定义在 javax.servlet
包下,主要是对客户端请求 HttpServletRequest
进行预处理,以及对服务器响应 HttpServletResponsen
进行后处理。Filter
接口源码如下
package javax.servlet;
import java.io.IOException;
public interface Filter {
default void init(FilterConfig filterConfig) throws ServletException {
}
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
default void destroy() {
}
}
该接口包含了 Filter
的 3
个生命周期:init()
、doFilter()
、destroy()
init()
:Servlet
容器在初始化Filter
时,会触发Filter
的init()
方法,一般来说是当服务启动时,这个方法只调用一次,用于初始化Filter
doFilter()
:当init()
方法初始化Filter
后,Filter
拦截到用户请求时,Filter
就开始工作了
void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
Servlet
容器会将用户请求封装成 ServletRequest
,而 doFilter()
参数中就 ServletRequest
,这也就意味着允许给 ServletRequest
增加属性或者增加 header
,也可以修饰 ServletReqest
或者 ServletResponse
来改变其行为
请注意最后一个参数 FilterChain var3
,该接口定义如下
public interface FilterChain {
void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}
该参数存在意味着,到达用户请求的真正方法之前,可能被多个过滤器进行过滤
,这时 Filter.doFilter()
方法将触发 Filter
链条中下一个 Filter
destroy()
:顾名思义,该方法就是在Servlet
容器要销毁Filter
时触发,一般在应用停止的时候调用
过滤器的配置
传统项目过滤器的配置
传统项目配置使用 filter
的主要 2
个步骤
- 实现
Filter
接口,实现其doFilter()
方法 - 在
web.xml
文件中使用<filter>
和<filter-mapping>
元素对编写的filter
类进行注册,并设置它所能拦截的资源 - 可以编写多个
Filter
,组成一个Filter
链,根据Filter
在web.xml
文件中的注册顺序,决定先调用哪个Filter
springboot
项目过滤器的配置
方式一:@WebServlet + @ServletComponentScan
注解
@WebFilter
注解开发过滤器
@WebFilter
用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器
@WebFilter(filterName = "HttpFilter2", urlPatterns = "/*")
public class HttpFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("HttpFilter2 init");
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("HttpFilter2 doFilter begin");
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
System.out.println("HttpFilter2 name:" + request.getParameter("name"));
// 将请求转发给过滤器链上下一个对象。这里的下一个指的是下一个filter,如果没有filter那就是请求的资源。
chain.doFilter(request, response);
System.out.println("HttpFilter2 doFilter end");
}
@Override
public void destroy() {
System.out.println("HttpFilter2 destroy");
Filter.super.destroy();
}
}
启动类增加 @ServletComponentScan
使用 @ServletComponentScan
注解后,Servlet、Filter、Listener
可以直接通过 @WebServlet、@WebFilter、@WebListener
注解自动注册
方式二:FilterRegistrationBean
注册
实现 Filter
接口
public class HttpFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("HttpFilter init");
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("HttpFilter doFilter begin");
HttpServletRequest req =(HttpServletRequest) request;
HttpServletResponse res =(HttpServletResponse) response;
System.out.println("HttpFilter name:" + request.getParameter("name"));
// 将请求转发给过滤器链上下一个对象。这里的下一个指的是下一个filter,如果没有filter那就是请求的资源。
chain.doFilter(request, response);
System.out.println("HttpFilter doFilter end");
}
@Override
public void destroy() {
System.out.println("HttpFilter destroy");
Filter.super.destroy();
}
}
在配置类中注册该过滤器
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<HttpFilter> httpFilter(){
FilterRegistrationBean<HttpFilter> filterRegistrationBean = new FilterRegistrationBean<HttpFilter>();
// 设置filter
filterRegistrationBean.setFilter(new HttpFilter());
// 拦截规则
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
Interceptor
和 Filter
小结
Filter
的执行顺序在Interceptor
之前Interceptor
是基于Java
的反射机制,而过滤器Filter
是基于函数回调Filter
能做的事情,Interceptor
都能做,而且可以在请求前,请求后执行,比较灵活