拦截器intercprot 和 过滤器 Filter 其实作用类似,可应用于:
1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间。
自定义拦截器实现 HandlerInterceptor 接口,也可以继承HandlerInterceptorAdapter。 实现接口需要实现对应的3中方法,继承父类只需要实现需要的方法即可。
HandlerInterceptor 接口:
public interface HandlerInterceptor {
/**
* preHandle方法是进行处理器拦截用的,顾名思义,该方法将在Controller处理之前进行调用,
* SpringMVC中的Interceptor拦截器是链式的,可以同时存在多个Interceptor,
* 然后SpringMVC会根据声明的前后顺序一个接一个的执行,
* 而且所有的Interceptor中的preHandle方法都会在Controller方法调用之前调用。
* SpringMVC的这种Interceptor链式结构也是可以进行中断的,
* 这种中断方式是令preHandle的返回值为false,当preHandle的返回值为false的时候整个请求就结束了。
*/
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
/**
* postHandle是进行处理器拦截用的,它的执行在Controller的方法调用之后执行,但是它会在DispatcherServlet进行视图的渲染之前执行,
* 也就是说在这个方法中你可以对ModelAndView进行操作。这个方法的链式结构跟正常访问的方向是相反的,
* 也就是说先声明的Interceptor拦截器该方法反而会后调用。
*/
void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
/**
* 该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。
* 该方法将在整个请求完成之后,也就是DispatcherServlet渲染了视图执行, 这个方法的主要作用是用于清理资源的,
*/
void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
}
通过也四张图可以看出:
1、如果一个拦截器的preHandle返回true,则该拦截器的afterCompletion方法一定会被调用。
public class DispatcherServlet extends FrameworkServlet{
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
Exception dispatchException = null;
try {
mappedHandler = getHandler(processedRequest);
//调用preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
//如果有拦截器preHandle返回false,程序不在向下执行。
return;
}
//调用controller中的方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//调用postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//处理程序调用的结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
/**
* 处理程序调用的结果
*/
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
//渲染视图
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
}
//调用afterCompletion方法
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
}
public class HandlerExecutionChain {
private final Object handler;
private HandlerInterceptor[] interceptors;//拦截器数组
private int interceptorIndex = -1;
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();//获取拦截器数组
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {//如果有拦截器preHandle返回false。
//触发拦截器的afterCompletion方法。
triggerAfterCompletion(request, response, null);
//后面的拦截器preHandle将不再执行
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//postHandle
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
}
过滤器和拦截器区别:
1、发生的时机不一样,filter是在servlet容器外,interceptor在servlet容器内,且可以对请求的3个关键步骤进行拦截处理。另外filter在过滤是只能对request和response进行操作,而interceptor可以对request、response、handler、modelAndView、exception进行操作。
2、拦截器不依赖与servlet容器,过滤器依赖与servlet容器
3、interceptor只能对action起作用,filter几乎对所有请求起作用。
测试用例:
@SpringBootApplication
@ServletComponentScan
@Controller
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@RequestMapping("/abcd")
@ResponseBody
public String index() {
System.out.println("helloWord");
return "helloWord";
}
}
@Order(1)
@WebFilter(urlPatterns = "/abcd/*",filterName = "myFilterOne")
class MyFilter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filter1_start");
long start=System.currentTimeMillis();
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("filter1_end_"+(System.currentTimeMillis()-start));
}
@Override
public void destroy() {
}
}
@Order(2)
@WebFilter(urlPatterns = "/abcd/*", filterName = "myFilterTwo")
class MyFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filter2_start");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("filter2_end" );
}
@Override
public void destroy() {
}
}
class MyInterceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("interceptor1_preHandle");
request.setAttribute("start", System.currentTimeMillis());
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("interceptor1_postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("interceptor1_afterCompletion_"+(System.currentTimeMillis()-(Long) request.getAttribute("start")));
}
}
class MyInterceptor2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("interceptor2_preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("interceptor2_postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("interceptor2_afterCompletion");
}
}
@Component
class MyInterceptorConfig extends WebMvcConfigurerAdapter {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/abcd/**");
registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/abcd/**");
}
}
结果: