亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

Spring MVC 數據模型(上)

1. 前言

本節課,將和大家一起聊聊 Spring MVC 在不同的作用域中如何封裝數據。

繼續之前,先理解本節課程提出的數據模型概念:Spring MVC 提供的在特定作用域內封裝數據的組件。掌握理解數據模型組件的使用便是全文重點。

2. 請求作用域

WEB 程序的應用層使用的是 HTTP 協議,HTTP 協議有一個特點,無狀態。

所謂無狀態指上一次請求與下一次請求之間是隔離的,沒有內在的聯系。更通俗的講,可理解為一個患有健忘癥的人,只記得當前自己在做什么,不記得自己曾經做過什么,更不會知道自己將來要做什么。

HTTP 協議的這種無狀態,最初設計時是從安全角度考慮。但是,在某些應用場景下,如購物車的應用場景下,卻顯得無能為力。購物車中的商品不一定是一次請求下的結果,往往是多次請求下的結果。

也就是說,購物車需要保存每一次請求獲取到的數據。顯然,直接使用 HTTP 協議是無法做到的。就需從技術層面上提供解決方案。

原生 Servlet 提供了 3 個作用域,可以根據用戶的需要來保存每一次請求過程中產生的數據。

  • 請求作用域: 使用 HttpServletRequest 組件存儲的數據可以在每一次的請求周期內存在。 請求結束,數據也將消失;
  • 會話作用域: 使用 HttpSession 組件保存的數據能在整個會話生命周期內存在。如購物車就可以保存在會話作用域中;
  • 應用程序作用域: 使用 ServletContext 組件保存的數據在整個應用程序生命周期之內存在。

Spring MVC 中,把數據保存在請求作用域,或是說在整個請求過程中數據都有效。有 2 種解決方案

  • 直接使用 HttpServletRequest 組件;
  • 使用 Spriing MVC 提供的高級數據模型組件。

2.1 使用原生 HttpServletRequest

先設定一個需要請求作用域的需求場景:

需求說明: 用戶登錄成功后,在登錄成功后的頁面中顯示登錄者的信息。

操作流程:

  1. 準備好 3 個靜態頁面;
  • login.html: 登錄頁面,接收用戶輸入的用戶名、密碼等與登錄相關的信息;
  • index.html: 登錄成功后跳轉到的頁面;
  • fail.html: 登錄失敗后跳轉到的頁面。
  1. 編寫 login.html 頁面中的登錄表單;
<form action="user/login" method="post">
   	姓名:<input name="userName" value="" type="text"> <br />
    密碼:<input name="userPassword" value="" type="password">
       <br />
       <input name="btnLogin" value="登錄" type="submit">
       <input name="btnRe" value="重置" type="reset">
</form>
  1. 編寫響應控制器;
@RequestMapping("/login")
public String login(User user,HttpServletRequest request) {
   	if("mk".equals(user.getUserName()) && "123".equals(user.getUserPassword())) {
   		//請求作用域	
	    request.setAttribute("loginUser", user);
	   	return "index";
   	}
   	return "fail";
}

login()方法有 2 個參數:

  • user 參數:OOP 的方式綁定請求包中傳過來的數據;
  • request 參數: 注入原生 HttpServletRequest 組件。Spring 的注入功能很厲害的,只要你需要,它便能幫你拿到。登錄者的信息保存在 HttpServletRequest 對象中。

Tips: HttpServletRequest 組件具有服務器端數據存儲功能,本質是內部維護有一個 map 對象。HttpServletRequest 的生命周期較短,從請求開始到請求結束。所以,其保存的數據也只能在整個請求范圍內有效。

  1. 編寫 index.html 和 fail.html 頁面。
  • idnex.html 頁面內,使用 EL 表達式,讀取請求作用域中的登錄者信息;
<body>
我是首頁
<br/>
當前登錄者:${loginUser.userName}
</body>

Tips: 這里有一個坑,需要提醒一下。通過 maven 創建的 WEB 項目的 web.xml 文件的頭信息版本偏低,使用 EL 表達式時,可能會在頁面中出現紅色的錯誤提示,其實并不影響發布。但終究讓人看的煩心??梢哉业?tomcat 服務器端的 web.xml 文件,用其頭信息替換下。

  • fail.html 頁面簡單地加入一條 “失敗” 提示語就可以了。

看一下最后的項目結構吧:

圖片描述

  1. 最后的測試。

Tips: 登錄的邏輯驗證使用了硬代碼,用戶名:mk,密碼:123。

登錄成功后,會轉到首頁,且在首頁中顯示出登錄者的信息。

圖片描述

2.2 使用 Spring MVC 模型組件

直接使用 HttpServletRequest 封裝請求作用域級別的數據,不能說不好。但是,Spring MVC 存在的目的,就是為了簡化開發者的工作,動不動就要 Spring 把底層的原生 API 弄出來,Spring MVC 存在的意義就不大了。

HttpServletRequest 的功能是全方面的,存儲數據可以說是它的副業,為了一個數據存儲,把它搬出來,好像有點大材小用。

其實,你可以告訴 Spring MVC ,我只要 HttpServletRequest 的存儲功能。也就是說,只要 Spring MVC 引用出 HttpServletRequest 內置的 map 對象就可以了。

圖片描述

好了!現在重構一下上面的實例,僅僅修改控制器 login()方法的代碼。

@RequestMapping(value="/login",method=RequestMethod.POST)
public String login(User user,Map map) {
   	if("mk".equals(user.getUserName()) && "123".equals(user.getUserPassword())) {
   		map.put("loginUser", user);
   		return "index";
   	}
   	return "fail";
}

還是 2 個參數,user 參數就不啰嗦了。

map 參數則是一個神奇的存在。在方法中一站,等于通知 Spring MVC ,幫我把某個作用域中的 map 對象引用出來。

如前言中所述,作用域有 3 個級別,Spring MVC 怎么知道你要哪一個層面的作用域。既然沒有明說,Spring MVC 引用出來的是請求作用域也就是 HttpServletRequest 的內置 map 對象。

好了,你可以放心的和前面一樣測試代碼,在 index.html 頁面中你將看到登錄者的信息。

搞了半天了,其實本質上是一樣:一個直接把 HttpServletRequest 交給你用,一個僅僅只是把實現了存儲的那一部分功能交給你。

有句話叫做透過現象看本質,Spring MVC 只是對原生 Servlet 開發做了高級封裝。如同端午節吃棕子,禮品盒再怎么高級、漂亮,打開后還是棕子。

3. 小結

本節課和大家一起學習了 Spring MVC 中的數據模型。所謂數據模型,就是用來裝數據的組件,當然,因 WEB 應用程序的特殊性,更多是要討論存放在這個組件中的數據在一個什么樣的范圍之內能夠被使用。

本節課學習到了,可以直接使用原生的 HttpServletRequest 完成請求作用域數據的存儲,觸類旁通,當然,你也可以直接使用原生 HttpSession 對象,保存會話作用域級別數據的保存。

有時,不需要為了吃一個桃子,砍掉一棵樹。開發者可以使用 Spring MVC 引用出內部的存儲對象,這樣更小巧實用。是的,本節課程中出現的 map 是 Spring MVC 中的數據模型組件。