在實際開發項目中,每每會有一種場景:好比須要往一類業務中加入共同的邏輯處理。由此springmvc引進了攔截器的概念。攔截器是動態攔截Action調用的對象。它提供了一種機制可使開發者能夠定義在一個action執行的先後執行的代碼,也能夠在一個action執行前阻止其執行,同時也提供了一種能夠提取action中可重用部分的方式,達到無需修改每一個處理器實現的目的。這就是咱們這一章須要介紹的HandlerInterceptorhtml
HandlerInterceptor實際上是在HandlerExecutionChain中引入的,在springmvc核心處理器DispatcherServlet的doDispatcher方法中請注意如下關於攔截器使用到的代碼java
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ... //預處理 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); //攔截器邏輯處理 mappedHandler.applyPostHandle(processedRequest, response, mv); ... //處理視圖 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); ... //視圖渲染徹底以後處理內容 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); } } } }
HandlerExecutionChain中包含了全部執行攔截器方法的代碼,web
/* * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.servlet; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; /** * Handler execution chain, consisting of handler object and any handler interceptors. * Returned by HandlerMapping's {@link HandlerMapping#getHandler} method. * * @author Juergen Hoeller * @since 20.06.2003 * @see HandlerInterceptor */ public class HandlerExecutionChain { private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class); private final Object handler; private HandlerInterceptor[] interceptors; private List<HandlerInterceptor> interceptorList; private int interceptorIndex = -1; /** * Create a new HandlerExecutionChain. * @param handler the handler object to execute */ public HandlerExecutionChain(Object handler) { this(handler, (HandlerInterceptor[]) null); } /** * Create a new HandlerExecutionChain. * @param handler the handler object to execute * @param interceptors the array of interceptors to apply * (in the given order) before the handler itself executes */ public HandlerExecutionChain(Object handler, HandlerInterceptor... interceptors) { if (handler instanceof HandlerExecutionChain) { HandlerExecutionChain originalChain = (HandlerExecutionChain) handler; this.handler = originalChain.getHandler(); this.interceptorList = new ArrayList<HandlerInterceptor>(); CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList); CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList); } else { this.handler = handler; this.interceptors = interceptors; } } /** * Return the handler object to execute. * @return the handler object */ public Object getHandler() { return this.handler; } public void addInterceptor(HandlerInterceptor interceptor) { initInterceptorList().add(interceptor); } public void addInterceptors(HandlerInterceptor... interceptors) { if (!ObjectUtils.isEmpty(interceptors)) { initInterceptorList().addAll(Arrays.asList(interceptors)); } } private List<HandlerInterceptor> initInterceptorList() { if (this.interceptorList == null) { this.interceptorList = new ArrayList<HandlerInterceptor>(); if (this.interceptors != null) { // An interceptor array specified through the constructor this.interceptorList.addAll(Arrays.asList(this.interceptors)); } } this.interceptors = null; return this.interceptorList; } /** * Return the array of interceptors to apply (in the given order). * @return the array of HandlerInterceptors instances (may be {@code null}) */ public HandlerInterceptor[] getInterceptors() { if (this.interceptors == null && this.interceptorList != null) { this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]); } return this.interceptors; } /** * Apply preHandle methods of registered interceptors. * @return {@code true} if the execution chain should proceed with the * next interceptor or the handler itself. Else, DispatcherServlet assumes * that this interceptor has already dealt with the response itself. */ 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)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; } /** * Apply postHandle methods of registered interceptors. */ void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = interceptors.length - 1; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(request, response, this.handler, mv); } } } /** * Trigger afterCompletion callbacks on the mapped HandlerInterceptors. * Will just invoke afterCompletion for all interceptors whose preHandle invocation * has successfully completed and returned true. */ 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); } } } } /** * Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors. */ void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = interceptors.length - 1; i >= 0; i--) { if (interceptors[i] instanceof AsyncHandlerInterceptor) { try { AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i]; asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler); } catch (Throwable ex) { logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex); } } } } } /** * Delegates to the handler's {@code toString()}. */ @Override public String toString() { if (this.handler == null) { return "HandlerExecutionChain with no handler"; } StringBuilder sb = new StringBuilder(); sb.append("HandlerExecutionChain with handler [").append(this.handler).append("]"); if (!CollectionUtils.isEmpty(this.interceptorList)) { sb.append(" and ").append(this.interceptorList.size()).append(" interceptor"); if (this.interceptorList.size() > 1) { sb.append("s"); } } return sb.toString(); } }
public interface HandlerInterceptor { boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception; }
攔截器的配置加在mvc:interceptors節點中,以下spring
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/user/**"/> <mvc:mapping path="/bind/**"/> <mvc:exclude-mapping path="/test/**"/> <bean class="com.kings.template.mvc.interceptor.Customer0Interceptor"/> </mvc:interceptor> <bean class="com.kings.template.mvc.interceptor.Customer1Interceptor"/> </mvc:interceptors>
mvc:interceptors下能夠添加多個mvc:interceptor或者bean,mvc:interceptor能夠設定攔截器攔截的路徑和不要攔截的路徑,而且提供對應的處理類,而若是在mvc:interceptors直接使用bean則會被所有攔截express
package com.kings.template.mvc.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Customer0Interceptor implements HandlerInterceptor{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("Customer0Interceptor 執行 preHandle預處理"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("Customer0Interceptor 執行 postHandle邏輯"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("Customer0Interceptor 執行 afterCompletion最終邏輯"); } }
package com.kings.template.mvc.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Customer1Interceptor implements HandlerInterceptor{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("Customer1Interceptor 執行 preHandle預處理"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("Customer1Interceptor 執行 postHandle邏輯"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("Customer1Interceptor 執行 afterCompletion最終邏輯"); } }
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/user/**"/> <mvc:mapping path="/bind/**"/> <mvc:exclude-mapping path="/test/**"/> <bean class="com.kings.template.mvc.interceptor.Customer0Interceptor"/> </mvc:interceptor> <bean class="com.kings.template.mvc.interceptor.Customer1Interceptor"/> </mvc:interceptors>
訪問http://localhost:8080/kingstemplate/user/1apache
打印信息以下mvc
Customer0Interceptor 執行 preHandle預處理 Customer1Interceptor 執行 preHandle預處理 [2016-10-22 14:27:11] [DEBUG] org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor(250) : Written [/Location] as "text/html" using [org.springframework.http.converter.StringHttpMessageConverter@2f412a47] Customer1Interceptor 執行 postHandle邏輯 Customer0Interceptor 執行 postHandle邏輯 [2016-10-22 14:27:11] [DEBUG] org.springframework.web.servlet.DispatcherServlet(1044) : Null ModelAndView returned to DispatcherServlet with name 'springmvc': assuming HandlerAdapter completed request handling Customer1Interceptor 執行 afterCompletion最終邏輯 Customer0Interceptor 執行 afterCompletion最終邏輯 [2016-10-22 14:27:11] [DEBUG] org.springframework.web.servlet.DispatcherServlet(1000) : Successfully completed request
過濾器能夠簡單理解爲「取你所想取」,忽視掉那些你不想要的東西;攔截器能夠簡單理解爲「拒你所想拒」,關心你想要拒絕掉哪些東西,好比一個BBS論壇上攔截掉敏感詞彙。app
1.攔截器是基於java反射機制的,而過濾器是基於函數回調的。less
2.過濾器依賴於servlet容器,而攔截器不依賴於servlet容器。async
3.攔截器只對action起做用,而過濾器幾乎能夠對全部請求起做用。
4.攔截器能夠訪問action上下文、值棧裏的對象,而過濾器不能。
5.在action的生命週期裏,攔截器能夠多起調用,而過濾器只能在容器初始化時調用一次。