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

Spring MVC 數據模型(下)

1. 前言

Spring MVC 為了解決 HTTP 協議的無狀態性,提供了很多能適用于不同作用域需求的模型對象,從而保證程序中的數據能在開發者需要的地方出現。

本節課繼續和大家聊聊 Spring MVC 中的數據模型組件。

  • Model;
  • ModelMap;
  • ModelAndView。

2. 更多數據模型

模型是一個用的很廣的概念。本課程中數據模型應該有 2 層含義:

  • WEB 程序中封裝數據的組件;
  • 此模型對象會有自己特定作用域。

上一小節中,向大家介紹了 Map 模型對象,其本質是對 HttpServletRequest 對象中的存儲功能的引用。Map 還是比較原始和天然的。Spring MVC 為了展現自己的特色服務,對 Map 進行了多層面的封裝,提供了更豐富的數據模型對象。

Tips: 重要的事情強調一下,你將認識或使用到的數據模型會很多,但其本質是:

  • 如果是請求作用域,你只是在間接使用 HttpServletRequest 對象;
  • 如果是會話作用域,你只是在間接使用 HttpSession 對象。

2.1 Model

這個字面意思很明顯,咱就是一個模型組件。

Model 是一個接口類型,Model 接口中提供了標準的保存數據的方法。

Model addAttribute(String attributeName, @Nullable Object attributeValue);

Model 使用起來很簡單,將 Model 設為控制器方法的參數便可 ,其它的交給 Spring MVC,因為 Model 是一個接口類型,Spring MVC 會為我們辨明身份,注入一個具體的實例對象。

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

Model 接口中還有其它的方法,但都不常用,感興趣的話大家可以查閱其源代碼或 API 文檔。

2.2 ModelMap

這個組件的字面意思是說,我是用 Map 存儲數據的模型??梢圆殚喴幌缕湓创a結構.,本質上還就是一個鏈表實現的 Map,都是一家人呀。

Map、Map …… 又見 Map。

ModelMap 中提供的方法和 Model 接口差不多,不同之處在于有自己的實現。

public class ModelMap extends LinkedHashMap<String, Object> {
	public ModelMap addAttribute(String attributeName, @Nullable Object attributeValue) {
		Assert.notNull(attributeName, "Model attribute name must not be null");
		put(attributeName, attributeValue);
		return this;
	} 
}

如何使用?

Spring MVC 的世界,會讓你感覺到自己的多余,因為很多事情 Spring MVC 都幫你溫柔的解決。一樣的,只需要設定為控制器方法的參數就可以了。

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

會發現,大家除了名字不一樣外,其它好像也沒有什么不一樣。

2.3 ModelAndView

從字面上了解這個組件,應該是除了充當模型的功能外,還與視圖有關系。想要徹底看透它,很簡單,查閱一下源代碼結構。

public class ModelAndView {
@Nullable
private Object view;
@Nullable
private ModelMap model;
//……
}

圖片描述

Tips: 搞了半天,會發現,ModelAndView 其實就是封裝了 ModelMap 外加一個用來保存視圖相關信息的 view 對象。

其實,大家都是一家人,根源是相同的,具有共同的遺傳基因,當然,還會有只屬于自己的獨有功能。

ModelAndView 和其它的數據模型使用起來稍有一點不同,往往是作為控制器方法的返回值。

@RequestMapping(value="/login",method=RequestMethod.POST)
public ModelAndView login01(User user) {
	ModelAndView mv=new ModelAndView();
	if("mk".equals(user.getUserName()) && "123".equals(user.getUserPassword())) {
		mv.addObject("loginUser", user);
		mv.setViewName("index");
		return mv;
	}
	mv.setViewName("fail");
	return mv;
}

Tips: ModelAndView 把數據模型和視圖拼在了一起,便于一次性交給前端控制器處理。

3. 會話作用域

Map、Model 、ModelMap、ModelAndView 這幾個數據模型組件,默認情況下,其中所保存的數據都是請求作用域級別的。

在很多應用場景下,需要數據在整個會話過程中都能訪問到。比如登錄者信息、購物車信息等。

面對這種數據需求時,Spring MVC 又如何實現?

你能想到的,Spring MVC 早就想到了。使用 @SessionAttributes 注解即可。

@SessionAttributes 注解是類級別的注解,需要添加在控制器類的前面。

@Controller
@RequestMapping("/user")
@SessionAttributes("loginUser")
public class UserAction {
@RequestMapping(value="/login",method=RequestMethod.POST)
	public ModelAndView login01(User user) {
	ModelAndView mv=new ModelAndView();
	if("mk".equals(user.getUserName()) && "123".equals(user.getUserPassword())) {
		mv.addObject("loginUser", user);
		mv.setViewName("index");
		return mv;
	}
	mv.setViewName("fail");
	return mv;
}
}

Tips: @SessionAttributes(“loginUser”) 中的屬性名 loginUser 必須保持和 mv.addObject(“loginUser”, user); 中的 loginUser 名一樣。

從底層思維來講, Spring MVC 即把數據保存到請求作用域中、也保存到會話作用域中。

測試時,只需要在 index.jsp 中添加如下面的 EL 表達式,指明數據的作用域。

<body>
 我是首頁
 <br/>
 請求作用域中得到當前登錄者:${requestScope.loginUser.userName}
 <br/>
 會話作用域中得到當前登錄者:${sessionScope.loginUser.userName}
</body>

啟動瀏覽器,打開登錄頁面,輸入登錄名、登錄密碼、點擊登錄,然后在瀏覽器中會看到無論是請求作用域、還是會話作用域中都可以獲取到登錄者的信息。

圖片描述

4. 小結

本節課程和大家一起講解了 Model 、ModelMap、ModelAndView 數據模型,并講解了可以使用 @SessionAttributes 注解提升數據模型的作用域。

從功能層面上講,所有數據模型組件的功能是一樣的。從底層上講,區別在于實現 Map 的數據結構。

  • 直接使用 Map 做數據模型時, Spring MVC 注入的是一個 LinkedHashMap 實例。
  • ModelMap 是 LinkedHashMap 的子類,本質還是 LinkedHashMap,只是封裝了 put 方法,讓其顯得高級一點。
  • Model 是接口,Spring MVC 注入的也是 LinkedHashMap 實例。

所以,無論是使用 Map 、Model 還是 ModelMap 其實都是在借助 LinkedHashMap 完成數據的存儲。其區別在于應用場景,有時,需要接口注入,有時可能需要類注入。當然,還會有自己的功能實現。