自定义拦截器,我们在开发中基本上都会用到,做一些权限控制,日志等等
下面用代码来解析下自定义拦截器
首先定义一个自定义拦截器
package com.asiainfo.springmvc.intercepter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.asiainfo.springmvc.controller.BaseController;
public class DefineIntercepter implements HandlerInterceptor{
private static final Logger logger = Logger.getLogger(BaseController.class);
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
logger.debug("测试拦截器preHandle");
return true;
}
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
logger.debug("测试拦截器postHandle");
}
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
logger.debug("测试拦截器afterCompletion");
}
}
在spring的xml文件中配置拦截管理器
<!-- 配置拦截器 -->
<mvc:interceptors>
<bean class="com.asiainfo.springmvc.intercepter.DefineIntercepter"></bean>
<!--
可以定义拦截器拦截某个指定的controller
比如我现在是配置url路径 是拦截local/*下面的所有请求,如果我变成format/testFormat,那么就不会被拦截
-->
<mvc:interceptor>
<mvc:mapping path="/locale/*"/>
<bean class="com.asiainfo.springmvc.intercepter.SecondIntercepter"></bean>
</mvc:interceptor>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
</mvc:interceptors>
结果:
DEBUG [http-bio-8888-exec-8] - 测试拦截器preHandle
DEBUG [http-bio-8888-exec-8] - 测试locale===========
DEBUG [http-bio-8888-exec-8] - 测试拦截器postHandle
DEBUG [http-bio-8888-exec-8] - Rendering view [org.springframework.web.servlet.view.JstlView: name 'success'; URL [/WEB-INF/jsp/success.jsp]] in DispatcherServlet with name 'springmvc'
DEBUG [http-bio-8888-exec-8] - Forwarding to resource [/WEB-INF/jsp/success.jsp] in InternalResourceView 'success'
DEBUG [http-bio-8888-exec-8] - 测试拦截器afterCompletion
从测试结果中,可以看出,拦截器的执行顺序
下面我们可以用源码来解读下,拦截器方法是在什么地方执行的
DispatcherServlet
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 || mappedHandler.getHandler() == 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 = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) { //从这里进入到mappedHandler ,看到拦截器的preHandle
return;
}
try {
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);//从这里进去看postHandle
}
}catch (Exception ex) {dispatchException = ex;}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);//视图渲染和数据处理
}catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}catch (Error err) {triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}finally {
if (asyncManager.isConcurrentHandlingStarted())
{// Instead of postHandle and afterCompletionmappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (getInterceptors() != null) {
for (int i = 0; i < getInterceptors().length; i++) {
HandlerInterceptor interceptor = getInterceptors()[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
从这个方法可以看出,在执行目标方法之前,就执行了这个前置拦截器方法,如果前置拦截器方法返回false,那么就不会执行目标方法,然后执行AfterCompletion拦截器方法,然后结束。
然后我们看第二个方法:
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
if (getInterceptors() == null) {
return;
}
for (int i = getInterceptors().length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
这个方法是目标方法的后面,但是在视图渲染的前面
第三个方法:
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);//这里指渲染视图
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);//第三个方法
}
这样就很简单明了,知道拦截器方法的执行顺序和过程