自定義攔截器:java
1、若想實現自定義攔截器,須要實現 org.springframework.web.servlet.HandlerInterceptor 接口。web
2、HandlerInterceptor APIspring
1. 接口中定義了三個方法express
2.preHandle() mvc
(1)調用時機app
在 org.springframework.web.servlet.DispatcherServlet#doDispatch 方法中。ide
org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle 具體的調用過程post
能夠看到,preHander() 方法的調用是在調用目標方法前調用的。性能
同時能夠看到,經過循環,調用了全部的攔截器,而且若是自定義的攔截器的 preHandler() 返回 false 的狀況下,仍是會去調用攔截器的 afterCompletion() 方法。spa
(2)能夠獲取到的資源
HttpServletRequest、HttpServletResponse、以及目標處理器。
3.postHandler()
(1)調用的時機
能夠看到在調用目標方法後,渲染視圖前調用的 postHandler() 方法。
具體的調用過程:
去調用每個攔截器的 postHandler() 方法,注意循環的方式,能夠看到攔截器棧 preHandler() 和 postHandler() 方法調用造成了一個 U 形。
(2)能夠獲取到的資源
HttpServletRequest、HttpServletResponse、目標hanler 處理器、以及返回的 ModelAndView 對象。
3.afterCompletion()
(1)調用時機
能夠看到,org.springframework.web.servlet.DispatcherServlet#doDispatch 執行邏輯的過程,捕獲到異常後,最終都是由攔截器的 afterCompletion() 方法進行的處理。
(2)能夠獲取到的資源
HttpServletReques, HttpServletResponse, 目標 handler 處理器, 全部的異常信息
4. HandlerInterceptor 家族
3、實現自定義的攔截器
1.繼承 HandlerInterceptorAdapter ,按照實際需求實現對應的方法就ok。
2.在 SpringMVC Config 文件中配置。
e1:
/** * @author solverpeng * @create 2016-09-01-15:56 */ public class FirstInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); } }
<mvc:interceptors> <bean class="com.nucsoft.springmvc.interceptor.FirstInterceptor"/> </mvc:interceptors>
說明:此種配置能夠攔截器全部請求。
e2:
/** * @author solverpeng * @create 2016-09-01-16:08 */ public class SecondInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("SecondInterceptor#preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("SecondInterceptor#postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("SecondInterceptor#afterCompletion"); } }
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/test/**"/> <bean class="com.nucsoft.springmvc.interceptor.SecondInterceptor"/> </mvc:interceptor> </mvc:interceptors>
說明:只會攔截路徑以 test 開頭的請求。如:http://localhost:8080/springmvc/test/testInterceptor02 會被 SecondInterceptor 攔截。
4、攔截器的幾個用處
1.性能監控
/** * 計算每次請求耗時 * @author solverpeng * @create 2016-09-01-17:46 */ public class ConsumeTimeInterceptor extends HandlerInterceptorAdapter{ // SpringMVC 是單例的,因此對於每一次請求,從 ThreadLocal 中獲取。 private NamedThreadLocal<Long> consumeTime = new NamedThreadLocal<>("consume_time"); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { consumeTime.set(System.currentTimeMillis()); System.out.println("ConsumeTimeInterceptor#preHandle"); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("ConsumeTimeInterceptor#afterCompletion"); Long threadEnd = System.currentTimeMillis(); Long threadStart = consumeTime.get(); Long consume = threadEnd - threadStart; if(consume > 10) { System.out.println("add to log: " + consume); } } }
<mvc:interceptors> <bean class="com.nucsoft.springmvc.interceptor.ConsumeTimeInterceptor"/> <bean class="com.nucsoft.springmvc.interceptor.FirstInterceptor"/> </mvc:interceptors>
控制檯輸出:
從中也能夠看出:攔截器的順序與 SpringMVC 中配置的順序是一致的。
2.登陸檢測
檢測用戶是否登陸。
異常處理:
1.局部的
在目標 handler 類中,聲明一個有 @ExceptionHandler 標註的方法,經過 @ExceptionHandler 的 value 的屬性來指定須要處理的異常類型。
能夠處理的異常能夠是一個類型,也能夠是多個類型。如:
@ExceptionHandler(value = {ArithmeticException.class}) @ExceptionHandler(value = {ArithmeticException.class, NullPointerException.class})
如:
@Controller public class SpringTest { @ExceptionHandler(value = {ArithmeticException.class}) public String handleArithmeticException(Exception ex) { System.out.println("spring test class"); ex.printStackTrace(); return "error"; } }
handleArithmeticException() 只能處理 SpringTest 控制器中出現的 ArithmeticException 類型的異常。
2.全局的
(1)基於註解
聲明一個統一的異常處理類:
須要對異常處理類添加 @ControllerAdvice 註解,對異常處理方法的標註還和局部的狀況同樣。如:
@ControllerAdvice public class HandlerException { @ExceptionHandler({ArithmeticException.class}) public String handlerArithmeticException(Exception ex) { ex.printStackTrace(); return "error"; } }
handlerArithmeticException() 能夠處理全部處理器發生的 ArithmeticException 類型的異常。
(2)基於xml
如:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" id="simpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="ArithmeticException">error</prop> </props> </property> </bean>
經過屬性 exceptionMappings 來指定要處理的異常,以及出現異常返回的頁面。
3.優先級
基於xml>局部>全局
4.如何在異常頁面獲得異常信息
request.getAttribute("javax.servlet.error.exception")
5.@ResponseStatus
能夠對全局的異常類標註 @ResponseStatus 註解,經過其 value 屬性來指定返回的 Http狀態碼。是 HttpStatus 枚舉類型。
來指定返回對應狀態碼的錯誤頁面。
父子容器配置:
SpringMVC 層容器能夠做爲 Spring 容器的子容器:
即 Web 層容器能夠引用業務層容器的 Bean,而業務層容器卻訪問不到 WEB 層容器 Bean。
SpringMVC Config:
<context:component-scan base-package="com.nucsoft.springmvc" use-default-filters="false"> <!-- 只掃描 @Controller 和 @ControllerAdvice 註解--> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/> </context:component-scan>
Spring Config:
<context:component-scan base-package="com.nucsoft.springmvc"> <!-- 不掃描 @Controller 和 @ControllerAdvice 註解--> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/> </context:component-scan>