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

来源:https://www.cnblogs.com/Open-ing/archive/2020/01/23/12230419.html
-Advertisement-
Play Games

SpringMVC 攔截器 Spring MVC也可以使用攔截器對請求進行攔截處理,可以自定義攔截器來實現特定的功能,自定義的攔截器可以實現HandlerInterceptor介面中的三個方法,也可以繼承HandlerInterceptorAdapter 適配器類按照需要那個方法,就實現哪個方法 過 ...


SpringMVC

攔截器

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

過濾器與攔截器區別

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

攔截器三個方法

  ① preHandle():這個方法在(Controller)處理器處理請求之前被調用,在該方法中對用戶請求 request 進行處理。如果該攔截器對請求進行攔截處理後還要調用其他的攔截器,或者是業務處理器去進行處理,則返回 true;如果不需要再調用其他的組件去處理請求,則返回false。(如果返回false則後續操作都不再執行,類似於過濾器的 doFilter 所以正常情況下不要返回 false)

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

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

配置攔截器

<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>

 程式執行順序

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

多個攔截器的執行流程

  當存在多個攔截器時的執行順序,由配置的先後順序決定。(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 次,可通過一個包含一個排除的方式解決


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 載入靜態資源 複習以前學的express express怎麼用? 如何獲取請求? 如何處理響應? 如何對向外暴露靜態資源? express核心:中間件:如何理解? 中間件:用來處理 http 請求的一個具體的環節(可能要執行某個具體的處理函數) 中間件一般都是通過修改 req 或者 res 對象來為 ...
  • 對babel進行複習
  • 不做解釋,代碼一看就懂 app.js config.js ...
  • 假如有兩個文件:app.js和config.js app.js為主文件要去引用config這個模塊 以前學習node時使用的模塊導出: es6中的模塊導出 方法一 兩種可以混合使用 方法二 通過 export 導出的成員必須通過解構賦值按需載入 或者通過 的形式載入所有通過 export 關鍵字導出 ...
  • 線上實時轉換 需要 .babelrc中: 項目中main.js配置: 前提是安裝對應的包 自己寫的要運行的為app.js,這樣配置後會在運行main.js是自動轉為es5並執行 通過配置手動轉換 需要 安裝babel後 運行 src為自己寫的es6目錄文件,dist為轉碼後的es5文件,沒有則創建 ...
  • 首先如果直接使用 root 用戶來啟動 tomcat 的話,是可以正常啟動的。 但是我們在 Linux 中使用普通用戶啟動 tomcat 報瞭如下錯誤 原因是沒有在 setclasspath.sh 上設置 JAVA_HOME 和 JRE_HOME。 解決辦法: 打開 setclasspath.sh ...
  • [toc] 一、入門 1、Spring Boot簡介 簡化Spring應用開發的一個框架 整個Spring技術棧的整合 J2EE開發的一站式解決方案 2、微服務 Martin Fowler 微服務是一種架構風格 一個應用應該是一組小型服務:可以通過HTTP的方式進行互通 每一個功能元素最終都是一個可 ...
  • 1. JDBC介紹 JDBC(Java DataBase Connectivity),即Java資料庫的連接。JDBC是一種用於執行SQL語句(DML,DDL,DQL)的Java API,可以為多種關係資料庫(oracle,mysql,sqlserver)提供統一訪問,它由一組用Java語言編寫的類 ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...