SpringMVC——拦截器

1.认识拦截器

在SpringMVC中,存在与Servlet中的过滤器(Filter)类似并且功能功能更加强大的拦截器(Interceptor)。它主要用于拦截用户请求并作相应的操作。可以简单理解为Spring中AOP的思想实现。在SpringMVC中,拦截器(HandlerInterceptor)是一个接口,我们使用时可以通过重写接口方法来完成我们想要做的事情。

public interface HandlerInterceptor {
    
    /*
    在控制器方法执行前运行该方法,返回值表示是否中断后续操作
    返回值:	true:继续向下执行
    		   false:会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)。
    */
	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 {
	}

}

2.配置拦截器

2.1 编写自己的拦截器

public class MyFirstHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyFirstHandlerInterceptor----preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyFirstHandlerInterceptor----postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyFirstHandlerInterceptor----afterCompletion");
    }
}

2.2 编写请求处理方法

@RequestMapping("/test11")
@ResponseBody
public String test11() {
    System.out.println("方法执行");
    return "success";
}

2.3 在SpringMVC.xml中注册我们的拦截器

<mvc:interceptors>
    <!--        方法一:给某些请求配置拦截器-->
    <mvc:interceptor>
        <mvc:mapping path="/test0*"/> 
        <mvc:exclude-mapping path="/test1*"/>
        <bean class="com.shang.HandlerInterceptor.MyFirstHandlerInterceptor"></bean>
    </mvc:interceptor>

    <!--        方法二:全部都进行配置-->
    <bean class="com.shang.HandlerInterceptor.MyFirstHandlerInterceptor"></bean>
</mvc:interceptors>
  • < mvc:interceptors > 元素用于配置一组拦截器,基子元素的bean中定义的是全局拦截器,他会拦截所有的请求
  • < mvc:interceptor >元素定义的是指定路径的拦截器
    • < mvc:mapping path= >指定拦截器作用的路径。”/**”表示拦截所有路径,“/test1 *” 表示拦截所有以 “/test1 *” 结尾的路径
    • < mvc:exclude-mapping path= > 指定拦截不包括那些路径

2.4 结果测试

在这里插入图片描述

3.多个拦截器执行顺序

定义两个拦截器,在SpringMVC.xml中如下配置

MyFirstHandlerInterceptor

public class MyFirstHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyFirstHandlerInterceptor----preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyFirstHandlerInterceptor----postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyFirstHandlerInterceptor----afterCompletion");
    }
}

MySecondHandlerInterceptor.java

public class MySecondHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MySecondHandlerInterceptor----preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MySecondHandlerInterceptor----postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MySecondHandlerInterceptor----afterCompletion");
    }
}

SpringMVC.xml

    <mvc:interceptors>
<!--        方法一:给某些请求配置拦截器-->
        <mvc:interceptor>
            <mvc:mapping path="/test*"/>
            <bean class="com.shang.HandlerInterceptor.MyFirstHandlerInterceptor"></bean>
        </mvc:interceptor>

<!--        方法二:全部都进行配置-->
        <bean class="com.shang.HandlerInterceptor.MySecondHandlerInterceptor"></bean>
    </mvc:interceptors>

3.1 每个拦截器全部放行

运行结果如下

在这里插入图片描述

我们通过输出可以看出,在SpringMVC.xml中进行配置的顺序就是我们拦截器执行的顺序,在退出控制器方法执行后,拦截器安装之前的顺序逆序退出,用符号来表示一下,就是这样的:

{ [ * ] }

3.2 第二个拦截器不放行

将MySecondHandlerInterceptor中的preHandle返回改为false

在这里插入图片描述

两个拦截器的perHandle执行了,但是我们可以看见MyFirstHandlerInterceptor的afterCompletion方法也执行了.且方法不执行,那这是为什么呢?

4.拦截器源码解析

在所有的请求发送过来时,都会执行DispatcherServlet.doDispatch方法,我们从这个方法开始了解拦截器的执行过程.

4.1 doDispatch方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request. 获得请求的处理器链
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request. 获得请求处理器的适配器
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = HttpMethod.GET.matches(method);
				if (isGet || HttpMethod.HEAD.matches(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

                //这里执行拦截器的preHandle方法,且这里传入的是一个拦截器链,如果返回false,不执行下面的方法,直接跳到finally处
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler. 真正执行执行器方法返回ModelAndView对象
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
                //这里执行拦截器链的postHandle的方法,逆序执行
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
            
            //视图结果返回到浏览器的执行
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
            //处理异常,在preHandle的控制中,返回false,就会执行.
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

4.2 applyPreHandle方法

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //对拦截器链进行遍历执行
    for (int i = 0; i < this.interceptorList.size(); i++) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        //如果preHandle返回值为false,退出方法执行
        if (!interceptor.preHandle(request, response, this.handler)) {
            triggerAfterCompletion(request, response, null);
            return false;
        }
        //记录执行到第几个拦截器链
        this.interceptorIndex = i;
    }
    return true;
}

4.3 applyPostHandle方法

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
    throws Exception {

    //从循环可以看出,为什么拦截器执行是逆序的
    for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        interceptor.postHandle(request, response, this.handler, mv);
    }
}

4.4 triggerAfterCompletion方法

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
    //这里就解释了为什么第二个拦截器挂了,第一个拦截器的afterCompletion方法还可以运行.
    //4.2-4.4的这些方法都存在于一个类中,interceptorIndex记录了最后执行到的拦截器
    for (int i = this.interceptorIndex; i >= 0; i--) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        try {
            interceptor.afterCompletion(request, response, this.handler, ex);
        }
        catch (Throwable ex2) {
            logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值