简述SpringMVC的拦截器Interceptor

什么是 Interceptor?

SpringMVC的拦截器HandlerInterceptor,针对调用Controller的请求,进行拦截和处理。

  • 我们首先自定义一个Interceptor
public class DemoInterceptor implements HandlerInterceptor {
	// 在进入控制器之前执行
	// 如果返回值为false,阻止进入控制器
	// 用途:拦截未登录请求;控制代码
	@Override
	public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
		//arg2是准备调用的Controller方法
		System.out.println("arg2=" + arg2);
		return true;
	}

	// 控制器执行完成,进入到jsp之前执行
	// 用途:日志记录;敏感词语过滤
	@Override
	public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
			throws Exception {
		//arg3.getViewName()可获得准备跳转的视图逻辑名 View
		System.out.println("往" + arg3.getViewName() + "跳转");
		//arg3.getModel()可获得视图数据 Model
		System.out.println("data1的值" + arg3.getModel().get("data1"));
		String word = arg3.getModel().get("data1").toString();
		String newWord = word.replace("色情", "**");
		arg3.getModel().put("data1", newWord);
		// arg3.getModel().put("data1", "修改后的内容");
	}

	// jsp执行完成后执行或Controller方法出现异常时执行
	// 用途:记录执行过程中出现的异常
	@Override
	public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
			throws Exception {
		// arg3是Controller方法中出现的异常
		System.out.println("arg3:" + arg3);
		if (arg3 != null) {
			//若是除零导致的,则arg3.getMessage()显示:/ by zero
			System.out.println( arg3.getMessage() );
		}
	}
}

我们从SpringMVC运行流程中也可以看出拦截器的生效时机:(留意中文注释即可)

	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		int interceptorIndex = -1;

		// Expose current LocaleResolver and request as LocaleContext.
		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		LocaleContextHolder.setLocaleContext(buildLocaleContext(request), this.threadContextInheritable);

		// Expose current RequestAttributes to current thread.
		RequestAttributes previousRequestAttributes = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request);
		RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);

		if (logger.isDebugEnabled()) {
			logger.debug("Bound request context to thread: " + request);
		}
		
		try {
			ModelAndView mv = null;
			try {
				processedRequest = checkMultipart(request);

				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest, false);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Apply preHandle methods of registered interceptors.
				// 调用拦截器中 preHandle方法
				HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
				if (interceptors != null) {
					for (int i = 0; i < interceptors.length; i++) {
						HandlerInterceptor interceptor = interceptors[i];
						if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
							triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
							return;
						}
						interceptorIndex = i;
					}
				}

				// Actually invoke the handler.
				// 适配器
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
				// ——————————— HandlerAdapter调用 Controller方法 ————————————
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				// Do we need view name translation?
				if (mv != null && !mv.hasView()) {
					mv.setViewName(getDefaultViewName(request));
				}

				// Apply postHandle methods of registered interceptors.
				// 调用拦截器的 postHandle方法
				if (interceptors != null) {
					for (int i = interceptors.length - 1; i >= 0; i--) {
						HandlerInterceptor interceptor = interceptors[i];
						interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
					}
				}
			}
			catch (ModelAndViewDefiningException ex) {
				logger.debug("ModelAndViewDefiningException encountered", ex);
				mv = ex.getModelAndView();
			}
			catch (Exception ex) {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				mv = processHandlerException(processedRequest, response, handler, ex);
			}

			// Did the handler return a view to render?
			if (mv != null && !mv.wasCleared()) {
				render(mv, processedRequest, response);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Null ModelAndView returned to DispatcherServlet with name '" +
							getServletName() + "': assuming HandlerAdapter completed request handling");
				}
			}

			// Trigger after-completion for successful outcome.
			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
		}

		catch (Exception ex) {
			// Trigger after-completion for thrown exception.
			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
			throw ex;
		}
		catch (Error err) {
			ServletException ex = new NestedServletException("Handler processing failed", err);
			// Trigger after-completion for thrown exception.
			triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
			throw ex;
		}

		finally {
			// Clean up any resources used by a multipart request.
			if (processedRequest != request) {
				cleanupMultipart(processedRequest);
			}

			// Reset thread-bound context.
			RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable);
			LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable);

			// Clear request attributes.
			requestAttributes.requestCompleted();
			if (logger.isDebugEnabled()) {
				logger.debug("Cleared thread-bound request context: " + request);
			}
		}
	}

springmvc.xml文件配置

	<!-- 拦截器 -->
	<mvc:interceptors>
		<!--拦截所有控制器 <bean class="com.ljm.interceptor.DemoInterceptor"></bean> -->

		<!-- 拦截特定的的url -->
		<mvc:interceptor>
			<mvc:mapping path="/demo" />
			<mvc:mapping path="/demo1" />
			<mvc:mapping path="/demo2" />
			<bean class="com.bjsxt.interceptor.DemoInterceptor"></bean>
		</mvc:interceptor>
	</mvc:interceptors>

拦截器栈

当多个拦截器同时生效时,将组成拦截器栈;执行顺序和Interceptor在 springmvc.xml 中的配置顺序有关。例:先配置拦截器 A 在配置拦截器 B 执行顺序为
preHandle(A) --> preHandle(B) --> 控制器方法 --> postHandle(B) --> postHanle(A) --> JSP --> afterCompletion(B) --> afterCompletion(A)
(先进后出)

猜你喜欢

转载自blog.csdn.net/sinat_33404263/article/details/105919794