三十四、面向對象底層邏輯-SpringMVC九大組件之FlashMapManager接口設計哲學

在構建符合 RESTful 原則或追求用戶體驗流暢性的 Web 應用時,“重定向后刷新”(PRG - Post/Redirect/Get)模式是避免表單重復提交、實現頁面無刷新跳轉的黃金法則。然而,重定向(REDIRECT:)的本質是客戶端發起一次全新的 GET 請求,原始請求中的數據(如成功/錯誤消息、表單暫存值)如何在兩次請求間安全傳遞?Spring MVC 的?FlashMapManager?接口及其配套機制,正是為解決這一核心痛點而生的優雅設計,它如同一位隱形的信使,在重定向的間隙悄然傳遞關鍵信息。

一、 核心挑戰:跨重定向請求的屬性傳遞

設想一個典型場景:

  1. 用戶提交表單(POST?/submit)。

  2. 服務器處理成功,需要重定向到結果頁面(GET?/result)以避免刷新導致重復提交。

  3. 同時,服務器需在結果頁面上顯示一條“操作成功”的消息。

問題核心:POST 請求處理過程中生成的“成功消息”如何安全、可靠地傳遞到后續的 GET 請求中?

  • HttpSession?直接存儲:可行但笨重。需手動存/取/清理屬性,易導致 Session 膨脹,并發場景需處理屬性命名沖突。

  • URL 拼接參數:如?/result?msg=Success。暴露信息、長度受限、不適用于敏感或復雜數據。

  • 請求轉發(Forward):能保留請求屬性,但瀏覽器地址欄不更新,刷新可能導致重新提交。

FlashMapManager?的設計目標清晰:提供一種輕量級、安全、自動清理的機制,在重定向操作前暫存數據,并在重定向后的目標請求中自動恢復這些數據,且僅限一次訪問

二、 FlashMap 與 FlashMapManager:協作的孿生核心

解決方案的核心是兩個緊密協作的組件:

  1. FlashMap:數據的載體容器。

  • 本質是一個?Map<String, Object>,用于存儲需要在重定向間傳遞的鍵值對(如?"successMessage" -> "操作成功!")。

  • 關鍵屬性:
    *?targetRequestPath:指定此?FlashMap?應應用到的目標請求路徑(可選,用于精確匹配)。
    *?expirationTime:設置過期時間戳,確保數據不會無限期駐留。

  1. FlashMapManager:接口定義管理?FlashMap?的生命周期。

public interface FlashMapManager {@NullableFlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response);
}
  • saveOutputFlashMap(FlashMap flashMap, ...)

    • 重定向發生前(通常在?DispatcherServlet?處理內部重定向邏輯時),由框架調用。

    • 職責:將當前請求上下文中準備好的?FlashMap?安全地存儲起來,供后續重定向請求檢索。

    • 存儲位置:通常基于?HttpSession?(默認實現),也可自定義(如分布式緩存)。

  • retrieveAndUpdate(HttpServletRequest request, ...)

    • 重定向后的目標請求到達時DispatcherServlet?開始處理新請求時),由框架調用。

    • 職責:

    1. 根據當前請求信息(如路徑、Session ID)查找匹配的?FlashMap

    2. 將找到的?FlashMap?中的數據提取并放入當前請求的屬性中(默認屬性名?DispatcherServlet.OUTPUT_FLASH_MAP_ATTRIBUTE)。

    3. 將已使用的?FlashMap?標記為過期或直接移除,確保數據僅被目標請求訪問一次。

    • 返回值:找到的?FlashMap(框架內部使用)。

三、 開發者視角:簡潔的 RedirectAttributes API

Spring MVC 并未讓開發者直接操作底層的?FlashMapManager?和?FlashMap,而是提供了更友好、更語義化的?RedirectAttributes?接口:

public interface RedirectAttributes extends Model {RedirectAttributes addFlashAttribute(String attributeName, @Nullable Object attributeValue);RedirectAttributes addFlashAttribute(Object attributeValue);// ... 其他方法如 addAttribute (會拼接到URL)
}

使用流程 (Controller 內)

  1. 準備重定向

    @PostMapping("/submit")
    public String handleSubmit(..., RedirectAttributes redirectAttrs) {// 業務處理...// 添加 Flash 屬性 (不暴露在URL)redirectAttrs.addFlashAttribute("successMessage", "數據保存成功!");// 添加普通屬性 (會拼接到重定向URL)redirectAttrs.addAttribute("id", savedEntity.getId()); // -> /result?id=123return "redirect:/result";
    }
  2. 在重定向目標中獲取

    @GetMapping("/result")
    public String showResult(Model model) {// Flash 屬性已由框架自動從 FlashMap 取出并添加到 Model 中!// 可直接在視圖中通過 ${successMessage} 訪問return "resultView";
    }

設計優勢

  • 高度抽象:開發者只需操作?RedirectAttributes,完全屏蔽?FlashMapManager?的復雜性。

  • 類型安全addFlashAttribute?方法清晰區分 Flash 數據與 URL 參數。

  • 自動集成:與 Spring MVC 的?Model?和視圖渲染無縫結合。

四、 核心實現:SessionFlashMapManager 剖析

Spring MVC 默認提供?org.springframework.web.servlet.support.SessionFlashMapManager,其工作原理如下:

  1. 存儲 (saveOutputFlashMap)

    • 獲取或創建當前 Session。

    • 從 Session 中獲取一個名為?FlashMapManager.FLASH_MAPS_SESSION_ATTRIBUTE?的?List<FlashMap>

    • 將待保存的?FlashMap?添加到這個 List 中。

    • 將更新后的 List 存回 Session。

  2. 檢索與更新 (retrieveAndUpdate)

    • 從當前請求的 Session 中獲取?List<FlashMap>

    • 遍歷 List

      • 檢查?FlashMap?是否過期 (expirationTime < currentTime)。

      • 檢查?targetRequestPath?是否匹配當前請求路徑(如果設置了)。

      • 如果找到匹配且未過期的?FlashMap

        • 將其數據放入當前請求的屬性中。

        • 將其從 List 中移除(確保一次性訪問)。

        • 將更新后的 List 存回 Session(移除了已使用的 FlashMap)。

    • 返回找到的?FlashMap?(內部使用)。

  3. 過期清理

    • retrieveAndUpdate?方法在查找時同步清理過期項。即使目標請求未觸發匹配,過期的?FlashMap?也會在下次任何請求調用?retrieveAndUpdate?時被清除。

    • 提供?setFlashMapTimeout(int seconds)?設置 FlashMap 默認存活時間(默認 180 秒)。

五、 設計精妙之處

  1. “一次性”語義保障:通過檢索后立即移除的機制,嚴格確保 Flash 屬性僅對重定向后的第一個請求可見。刷新?/result?頁面不會再次顯示消息,符合 PRG 模式預期。

  2. 請求隔離與精確投遞

    • targetRequestPath?允許將 Flash 數據精準關聯到特定目標 URL,避免在無關請求中泄露。

    • 基于 Session ID 的存儲自然隔離不同用戶的數據。

  3. 自動垃圾回收:內置的過期檢查和清理機制有效防止 Session 因殘留 FlashMap 而膨脹。

  4. 可插拔的存儲策略FlashMapManager?是接口。默認?SessionFlashMapManager?適用于大多數應用。在分布式/無狀態場景下,可輕松實現基于 Redis、Memcached 或數據庫的?FlashMapManager?替代 Session 存儲。

  5. 與框架深度集成

    • DispatcherServlet?在內部流程關鍵點(處理重定向前、處理新請求前)自動調用?FlashMapManager?的方法。

    • RequestMappingHandlerAdapter?在調用 Controller 方法前,將檢索到的 FlashMap 數據合并到?Model?中。

六、 最佳實踐與考量

  • 內容類型:適合傳遞短小、非敏感的即時消息(成功/失敗提示)、表單校驗錯誤對象(BindingResult)、或少量需要在重定向后頁面顯示的臨時狀態數據切勿用于傳遞大型對象或敏感信息。

  • 命名規范:使用清晰、一致的屬性名(如?message,?errorMessage,?info)。

  • 分布式環境:默認?SessionFlashMapManager?依賴 Session 親和性(Sticky Session)。在集群部署且 Session 不共享時,必須實現自定義的分布式?FlashMapManager

  • 自定義實現:實現?FlashMapManager?接口,重寫?saveOutputFlashMap?和?retrieveAndUpdate?方法,選擇所需的存儲后端(如 Redis)。注冊自定義 Bean 覆蓋默認實現。

  • 測試:Spring 提供了?MockFlashMapManager?方便單元測試 Controller 中的重定向和 Flash 屬性邏輯。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/83876.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/83876.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/83876.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

android手勢創建及識別保姆級教程

手勢交互&#xff0c;簡單來說&#xff0c;就是通過手指在屏幕上的滑動、點擊、縮放等動作與設備溝通的方式&#xff0c;早已成為現代移動設備用戶體驗的核心支柱。想想看&#xff0c;無論是日常刷短視頻時的上下滑動&#xff0c;還是地圖導航時的雙指縮放&#xff0c;甚至是游…

Python | Windows11通過離線方式安裝pyserial

導言 因公司網絡訪問的限制&#xff0c;沒辦法使用pip install pyserial輕松地安裝pyserial庫。 打開網頁&#xff1a;https://pypi.org/project/pyserial/#files 下載.whl cmd命令行 如下是命令行指令&#xff1a; pip install .\pyserial-3.5-py2.py3-none-any.whlpython …

【nano與Vim】常用命令

使用nano編輯器 保存文件 &#xff1a; 按下CtrlO組合鍵&#xff0c;然后按Enter鍵確認文件名。 退出編輯器 &#xff1a; 按下CtrlX組合鍵。 使用vi或vim編輯器 保存文件 &#xff1a; 按Esc鍵退出插入模式&#xff0c;然后輸入:w并按Enter鍵保存文件。 退出編輯器 &#xf…

(Python網絡爬蟲);抓取B站404頁面小漫畫

目錄 一. 分析網頁 二. 準備工作 三. 實現爬蟲 1. 抓取工作 2. 分析工作 3. 拼接主函數&運行結果 四. 完整代碼清單 1.多線程版本spider.py&#xff1a; 2.異步版本async_spider.py&#xff1a; 經常逛B站的同志們可能知道&#xff0c;B站的404頁面做得別具匠心&…

實戰設計模式之模板方法模式

概述 模板方法模式定義了一個操作中的算法骨架&#xff0c;并將某些步驟延遲到子類中實現。模板方法使得子類可以在不改變算法結構的前提下&#xff0c;重新定義算法中的某些步驟。簡單來說&#xff0c;就是在一個方法中定義了要執行的步驟順序或算法框架&#xff0c;但允許子類…

ROS1: 使用rosbag的方式將點云topic保存為pcd文件

ROS1: 使用rosbag的方式將點云topic保存為pcd文件。 分為兩步&#xff1a;步驟1&#xff1a;通過rosbag錄制點云 &#xff0c;步驟2&#xff1a;通過ros1將rosbag保存為點云pcd文件。 ------------------------ 步驟一&#xff1a;指令示例如下&#xff1a; # topic 名稱&a…

MySQL 高級學習篇

一、連結&#xff08;Join&#xff09; 1.1 概念 聯結&#xff08;Join&#xff09;操作用于將多個表中的列組合在一起&#xff0c;形成一個新的查詢結果集。它允許我們從多個表中提取數據&#xff0c;并基于表之間的關系進行查詢。 1.2 類型 1. 內聯結&#xff08;INNER J…

clickhouse 學習總結

在 ClickHouse 中&#xff0c;配置文件通常位于 /etc/clickhouse 目錄下。這個目錄包含了多個配置文件&#xff0c;用于控制 ClickHouse 的各種服務&#xff08;如服務器、用戶、遠程服務等&#xff09;的配置。 數據存儲目錄/var/lib/clickhouse 配置 文件目錄 /etc/clickho…

理解JavaScript中map和parseInt的陷阱:一個常見的面試題解析

前言 在JavaScript面試中&#xff0c;map和parseInt的組合常常被用作考察候選人對這兩個方法理解深度的題目。讓我們通過一個簡單的例子來深入探討其中的原理。 問題現象 [1, 2, 3].map(parseInt) // 輸出結果是什么&#xff1f;很多人可能會預期輸出[1, 2, 3]&#xff0c;但…

字符串 金額轉換

package heima.Test09;import java.util.Scanner;public class Money {public static void main(String[] args) {//1。鍵盤錄入一個金額Scanner sc new Scanner(System.in);//請輸入一個數據String result "";int money;while (true) {System.out.println("請…

靜態相機中的 CCD和CMOS的區別

文章目錄 CCD處理方式CMOS處理方式兩者區別 首先根據 成像原理&#xff0c;CCD和CMOS的作用是一致的&#xff0c;都是為了將光子轉化為數字圖像&#xff0c;只是 轉換的方式出現差異。 CCD處理方式 獲取光子&#xff1a; 在電荷耦合器件&#xff08;CCD&#xff09;傳感器中…

Pycharm的終端無法使用Anaconda命令行問題詳細解決教程

很多初學者在Windows系統上安裝了Anaconda后&#xff0c;在PyCharm終端中運行Conda命令時&#xff0c;會遇到以下錯誤&#xff1a; conda : 無法將“conda”項識別為 cmdlet、函數、腳本文件或可運行程序的名稱。 請檢查名稱的拼寫&#xff0c;如果包括路徑&#xff0c;請確保…

[大語言模型]在個人電腦上部署ollama 并進行管理,最后配置AI程序開發助手.

ollama官網: 下載 https://ollama.com/ 安裝 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token數量為409622 16384 ollama命令說明 ollama serve #&#xff1a…

TDengine 替換 Hadoop,徹底解決數據丟失問題 !

完全替換 Hadoop&#xff0c;徹底解決寫入丟數問題 &#xff01;TDengine 助力積成電子更好服務電力客戶&#xff01; 小T導讀&#xff1a;在內蒙古某新能源集控項目中&#xff0c;三區需接入并分析大量風電、光伏逆變器及儲能設備的監測數據。隨著數據規模不斷擴大&#xff0c…

從0到1認識ElasticStack

一、ES集群部署 操作系統Ubuntu22.04LTS/主機名IP地址主機配置elk9110.0.0.91/244Core8GB100GB磁盤elk9210.0.0.92/244Core8GB100GB磁盤elk9310.0.0.93/244Core8GB100GB磁盤 1. 什么是ElasticStack? # 官網 https://www.elastic.co/ ElasticStack早期名稱為elk。 elk分別…

MySQL賬號權限管理指南:安全創建賬戶與精細授權技巧

在MySQL數據庫管理中&#xff0c;合理創建用戶賬號并分配精確權限是保障數據安全的核心環節。直接使用root賬號進行所有操作不僅危險且難以審計操作行為。今天我們來全面解析MySQL賬號創建與權限分配的專業方法。 一、為何需要創建獨立賬號&#xff1f; 最小權限原則&#xf…

DFT測試之TAP/SIB/TDR

TAP的作用 tap全稱是test access port&#xff0c;是將jtag接口轉為reset、sel、ce、ue、se、si、tck和so這一系列測試組件接口的模塊。 jtag的接口主要是下面幾個信號&#xff1a; 信號名稱信號方向信號描述TCK&#xff08;測試時鐘&#xff09;輸入測試時鐘&#xff0c;同…

Python對接印度股票數據源實戰指南

Python對接印度股票數據源實戰指南 基于StockTV API實現印度證券市場數據對接&#xff0c;覆蓋實時行情、K線、指數等核心功能&#xff0c;提供完整開發方案與避坑指南 一、數據源選型要點&#xff08;技術維度對比&#xff09; 根據2025年最新實測數據&#xff0c;印度市場主…

usbutils工具的使用幫助

作為嵌入式系統開發中的常用工具&#xff0c;usbutils 是一套用于管理和調試USB設備的Linux命令行工具集。以下是其核心功能和使用方法的詳細說明&#xff1a; 1. 工具組成 核心命令&#xff1a; lsusb&#xff1a;列出所有連接的USB設備及詳細信息&#xff08;默認安裝&#…

k8s入門教程(集群部署、使用,鏡像拉取失敗網絡問題排查)

文章目錄 K8S基礎創建centos虛擬機K3S部署配置k3s容器containerd鏡像2025年4月測試可用鏡像源配置 Pod容器Deployment&#xff08;部署&#xff09;和ReplicaSet&#xff08;副本集&#xff09;鏡像拉取失敗問題排查 Service服務ServiceType取值 NameSpace命名空間聲明式對象配…