Java框架之SpringMVC 05-攔截器-異常映射-Spring工做流程

SpringMVC

攔截器

  Spring MVC也可使用攔截器對請求進行攔截處理,能夠自定義攔截器來實現特定的功能,自定義的攔截器能夠實現HandlerInterceptor接口中的個方法也能夠繼承HandlerInterceptorAdapter 適配器類按照須要那個方法,就實現哪一個方法html

過濾器與攔截器區別前端

  過濾器:過濾器在Servlet以前操做
  攔截器:攔截器在Servlet以後,請求處理器(Controller)以前操做。java

攔截器三個方法web

  ① preHandle():這個方法在(Controller)處理器處理請求以前被調用,在該方法中對用戶請求 request 進行處理。若是該攔截器對請求進行攔截處理後還要調用其餘的攔截器,或者是業務處理器去進行處理,則返回 true;若是不須要再調用其餘的組件去處理請求,則返回false。(若是返回false則後續操做都再也不執行,相似於過濾器的 doFilter 因此正常狀況下不要返回 false)spring

  ② postHandle():這個方法在(Controller)處理器處理完請求後,可是 DispatcherServlet 向客戶端返回響應前(在視圖渲染以前)被調用,在該方法中對用戶請求request進行處理。服務器

  ③ afterCompletion():這個方法在 DispatcherServlet 徹底處理完請求後(轉發|重定向 以後)被調用,能夠在該方法中進行一些資源清理關閉的操做。mvc

配置攔截器app

<mvc:interceptors>
        <!--   爲全部請求設置攔截器 也可用 ref 引用已經裝配好的攔截器-->
        <bean id="firstHandlerInterceptor" class="main.controller.FirstHandlerInterceptor"></bean>
        <mvc:interceptor>
            <!--     表示指定攔截器只攔截/test/下的全部請求-->
            <mvc:mapping path="/test/**/"/>
            <!--     表示訪問/test/test.do的請求不會觸發攔截器-->
            <mvc:exclude-mapping path="/test/test.do"/>
         <!--     爲指定的請求設置攔截器 也可用 ref 引用已經裝配好的攔截器-->
         <bean id="testInterceptor" class="main.controller.TestInterceptor"></bean> 
        </mvc:interceptor> 
</mvc:interceptors>

 程序執行順序post

  1. preHandle():執行請求處理器的請求(Controller)方法以前執行。 
  2. 執行請求處理器的請求(Controller)方法
  3. postHandle():執行請求處理器的請求(Controller)方法以後,在視圖渲染以前。
  4. 視圖渲染
  5. afterCompletion():視圖渲染(轉發|重定向)以後執行。spa

多個攔截器的執行流程

  當存在多個攔截器時的執行順序,由配置的前後順序決定。(preHandle() 先配置,先執行) 
  preHandle():與攔截器配置的前後順序一致
  postHandle():與攔截器配置的前後順序相反。底層倒序循環調用的
  afterCompletion():與攔截器配置的前後順序相反。

preHandle()返回值爲false時的工做原理

  第一個攔截器的preHandle()的返回值爲false:
    只執行第一個攔截器的prehandle()方法,執行完,return;(後續的方法都不執行) 
  不是第一個攔截器的preHandle()的返回值爲false: 
    當前攔截器以前的攔截器的afterCompletion()都會被執行。

  當兩個攔截器的 preHandle() 方法都返回 true 時,按照虛線路執行

  當第二個攔截器 preHandle() 方法返回 false 時按照實現路線執行

 異常處理

  在SpringMVC中,不管請求控制器中是否存在異常,都會返回ModelAndView對象

  Spring MVC 經過 HandlerExceptionResolver  處理程序的異常,包括 Handler 映射、數據綁定以及目標方法執行時發生的異常

  DispatcherServlet  默認裝配的 HandlerExceptionResolver 有 DefaultHandlerExceptionResolver 解析器會自動將標準的Spring MVC異常解析爲HTTP錯誤狀態碼

  使用 <mvc:annotation-driven/> 配置會裝配Spring3.0後新增的異常解析器,實現更精細化處理。若是但願對全部異常進行統一處理或指定某一異常跳轉頁面,可使用 SimpleMappingExceptionResolver,它將異常類名映射爲視圖名,可實現跳轉到指定頁面,並報告異常.

配置異常解析器

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <!--    爲全部異常定義默認的處理頁面,exceptionMappings未定義的,
                value表示跳轉頁面,至於文件路徑和後綴已經在 viewResolver 中指定-->
        <property name="defaultErrorView" value="error"></property>
        <!--    定義異常處理頁面用來獲取異常信息的變量名,被存放到 request 域中-->
        <property name="exceptionAttribute" value="exception"></property>
        <!--    須要特殊處理的異常,全類名做爲key,異常頁文件名做爲值,可將不一樣的異常映射到不一樣的頁面上-->
        <property name="exceptionMappings">
            <props>
                <prop key="java.lang.NullPointerException">nullPointer</prop>
            </props>
        </property>
    </bean>

<mvc:annotation-driven/>

  是spring MVC爲@Controllers分發請求所必須的,即啓用註解驅動,解決了@Controller註解使用的前提配置。

  同時它還提供了:數據綁定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,讀寫XML的支持(JAXB,讀寫JSON的支持(Jackson)。

  它會自動爲咱們註冊了不少的Bean,最重要的就是RequestMappingHandlerMappingRequestMappingHandlerAdapter

    第一個是HandlerMapping的實現類,它會處理@RequestMapping 註解,並將其註冊到請求映射表中。
    第二個是HandlerAdapter的實現類,它是處理請求的適配器,說白了,就是肯定調用哪一個類的哪一個方法,而且構造方法參數,返回值。

  簡單的說,用什麼註解,就須要聲明對應的BeanPostProcessor。而Spring爲咱們提供了一種極爲方便註冊這些BeanPostProcessor的方式,即便用各類標籤來隱式地向 Spring 容器註冊

Spring工做流程

  相關類

    HandlerMapping(請求處理器的映射對象):定義了一個全部請求和請求處理器對象之間的映射關係對象

    HandlerExecutionChain(請求處理器執行鏈對象):定義了 當前請求處理器對象,和全部攔截器對象。

    HandlerAdapter(請求處理器的適配器對象):調用當前請求處理器的請求方法。

  執行流程對應下圖理解

    1)用戶向服務器發送請求,請求被SpringMVC 前端控制器 DispatcherServlet捕獲

    2)DispatcherServlet對請求URL進行解析,獲得請求資源標識符(URI):判斷請求URI對應的映射
      ① 不存在:
        再判斷是否配置了 mvc:default-servlet-handler:
        若是沒配置,則控制檯報映射查找不到,客戶端展現404錯誤
        若是有配置,則執行目標資源(通常爲靜態資源,如:JS,CSS,HTML)
      ② 存在:
        執行下面流程

    3)根據該URI,調用HandlerMapping得到該Handler配置的全部相關的對象(包括Handler對象以及Handler對象對應的攔截器),最後以HandlerExecutionChain對象的形式返回;

    4)DispatcherServlet 根據得到的Handler,選擇一個合適的HandlerAdapter。

    5)若是成功得到HandlerAdapter後,此時將開始執行攔截器的preHandler(...)方法【正向】

    6)提取Request中的模型數據,填充Handler入參,開始執行Handler(Controller)方法,處理請求。在填充Handler的入參過程當中,根據你的配置,Spring將幫你作一些額外的工做:
      ① HttpMessageConveter: 將請求消息(如Json、xml等數據)轉換成一個對象,將對象轉換爲指定的響應信息
      ② 數據轉換:對請求消息進行數據轉換。如String轉換成Integer、Double等
      ③ 數據格式化:對請求消息進行數據格式化。 如將字符串轉換成格式化數字或格式化日期等
      ④ 數據驗證: 驗證數據的有效性(長度、格式等),驗證結果存儲到BindingResult或Error中

    7)Handler執行完成後,向DispatcherServlet 返回一個ModelAndView對象;

    8)此時將開始執行攔截器的postHandle(...)方法【逆向】

    9)根據返回的ModelAndView(此時會判斷是否存在異常:若是存在異常,則執行HandlerExceptionResolver進行異常處理)選擇一個適合的ViewResolver(必須是已經註冊到Spring容器中的ViewResolver)返回給DispatcherServlet,根據Model和View,來渲染視圖

    10)在返回給客戶端時須要執行攔截器的AfterCompletion方法【逆向】

    11)將渲染結果返回給客戶端

 

Spring與SpringMVC

  spring容器與springMVC容器對象的關係

    springMVC容器對象,默認交個DispatcherServlet管理

    spring容器對象,須要咱們管理(交給Listener管理)

  spring容器對象描述

    Root WebApplicationContext: root of context hierarchy

  springMVC容器對象描述

    WebApplicationContext for namespace 'springDispatcherServlet-servlet':root of context hierarchy

  spring容器對象是父,springMVC容器對象是子。子類能夠直接調用父類方法。

  SpringMVC 的 IOC 容器中的 bean 能夠引用 Spring IOC 容器中的 bean.反之則不行. 

  在web應用下,獲取spring容器對象方式

ServletContext servletContext = httpSession.getServletContext();
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);

 

  在web應用下,獲取springMVC容器對象可直接經過裝配屬性的方式獲取

    @Autowired
    private XmlWebApplicationContext context;

配置文件

  若 Spring 的 IOC 容器和 SpringMVC 的 IOC 容器掃描組件的包有重合的部分, 就會致使有的 bean 會被建立 2 次,可經過一個包含一個排除的方式解決

相關文章
相關標籤/搜索