Spring MVC 3.1 版本增添了Flash Attribute的新特性,解決了一直以來關於POST請求後跳轉頁面導致原有用戶傳入的數據無法續存的問題。
Flash Attribute
講解這個知識點前, 先要理解瀏覽器的所謂「刷新」的本質是什麼。
瀏覽器刷新的本質是將你上一次發送的HTTP請求重新發送一次。
比如你現在在url地址欄中輸入一個網址,打開了這個網址對應的頁面,按下了F5,瀏覽器會重新發送一次你的url指定的HTTP請求,但是這種刷新方式也引來了一定的問題。
F5
我之前的一篇文章,
中, 就遇到了這個問題。
這個例子很簡單,就是註冊賬號(POST請求,將用戶名、密碼、郵箱存到資料庫中),登陸賬號。
如圖所示:
那麼如果我現在在註冊新賬號底下填寫了必要信息, 點擊了註冊之後, 我會向伺服器發送一個POST請求, 這個POST請求即包含了url, 又包含了我們傳入了表單信息, 那麼如果我現在點擊刷新, 剛才的POST請求會再次進行一遍,也就是重新註冊一次賬號,如果Controller的方法里沒有要求郵箱不可重複的話,資料庫中就會存儲上兩個一模一樣的賬號信息,比如我現在註冊一個新賬號:
註冊新賬號
註冊
POST
url
表單信息
Controller
點擊了註冊後, 我刷新一下頁面, 再返回, 我會發現資料庫中有兩組相同的數據:
如何避免這種現象呢?
那就是使用Redirect方法,讓用戶提交了表單數據後,返回一個Redirect回應, 強制讓用戶側自動進行一次Get請求, 這樣當用戶再次刷新的時候, 就不會重新提交一次表單數據了, 所以我們只需再Controller方法中增加跳轉功能:
Redirect
Get
@PostMapping(path = "/add") public String addNewUser (@RequestParam String name , @RequestParam String email, @RequestParam String password, User user) { user.setName(name); user.setEmail(email); user.setPassword(password); userRepository.save(user); log.info(user.toString()+" saved to the repo"); return "redirect:/"; }
我將返回值改成了redirect:/, 也就是當用戶提交了表單信息後, 該方法會返回一個redirect:/的response, 強制讓用戶進行跳轉, 跳轉到入口界面, 也就是根目錄的位置, 用一個圖來解釋這個原理:
redirect:/
response
當用戶填寫了表單, 提交了數據, 服務端將數據存在數據空中, 然後發送了讓用戶跳轉的指令, 然後用戶自動用GET方法跳轉到另一個頁面, 這樣當用戶刷新的時候, 就會重新發送GET方法, 而不是之前的POST。
GET
但是這樣一來又出來一個問題, 就是我無法直接將用戶提交的表單數據顯示在跳轉後的頁面, 比如我想在用戶登陸後, 在跳轉後的頁面標題上顯示Hello, 用戶名, 但是因為Spring MVC的M層僅僅是對當前的請求有效, 你將用戶名的信息存在Model里, 然後再跳轉, 跳轉後的那個Controller方法是不會得到你上一個Model里的信息的, 這就是為什麼我們要引入Flash Attribute。
Hello, 用戶名
Flash Attribute里保存的信息會傳入下一個跳轉頁面的Model里,或者這麼說: 對於一個Controller層的映射方法來說, 它目前儲存的Flash Attribute是來自於上一個頁面, 也就是由其跳轉來的頁面, 而在當前方法中儲存的Flash Attribute會傳入下一個即將跳轉過去的頁面里,有了它,我們便解決了這個問題。
Model
看這個圖:
FlashMap是用來以Key-Value形式儲存Flash Attribute的API, 而FlashMapManager則是用來儲存, 獲取, 管理FlashMap實例的API。
FlashMap
Key-Value
FlashMapManager
對於剛才列出的Controller代碼,我們再做如下改動
@PostMapping(path = "/add") // Map ONLY GET REQUESTs. public String addNewUser (@RequestParam String name , @RequestParam String email, @RequestParam String password, User user, RedirectAttributes redirectAttributes) { // @ResponseBody means the returned String is a response, not a view name. user.setName(name); user.setEmail(email); user.setPassword(password); userRepository.save(user); redirectAttributes.addFlashAttribute("username", name); log.info(user.toString()+" saved to the repo"); return "redirect:/"; }
在方法傳入參數中加一個RedirectAttributes, 然後在代碼中給redirectAttributes增加一個key="username"的FlashAttribute, value為用戶在表單數據中填寫的用戶名。
RedirectAttributes
redirectAttributes
key="username"
FlashAttribute
value
然後跳轉後,我們的主頁面便會顯示:
希望大家能有所收穫。
TAG:SpringMVC | Spring | SpringBoot |