SpringMVC 處理數據模型


處理模型數據

Spring MVC 提供了以下幾種途徑輸出模型數據:

  ModelAndView: 處理方法返回值類型為 ModelAndView 時, 方法體即可通過該對象添加模型數據
  Map 及 Model: 入參為org.springframework.ui.Model、org.springframework.ui.ModelMap 或 java.uti.Map 時,處理方法返回時,Map 中的數據會自動添加到模型中。
  @SessionAttributes: 將模型中的某個屬性暫存到 HttpSession 中,以便多個請求之間可以共享這個屬性
  @ModelAttribute: 方法入參標注該注解后, 入參的對象就會放到數據模型中

ModelAndView

控制器處理方法的返回值如果為 ModelAndView, 則其既包含視圖信息,也包含模型數據信息。

SpringMVC 會把 ModelAndView 的 model 中數據放入到 request 域對象中.

添加模型數據:
  MoelAndView addObject(String attributeName, Object attributeValue)
  ModelAndView addAllObject(Map<String, ?> modelMap)

設置視圖:
  void setView(View view )
  void setViewName(String viewName)

 1     @RequestMapping("/testModelAndView")
 2     public ModelAndView testModelAndView(){
 3         String viewName = SUCCESS;
 4         ModelAndView modelAndView = new ModelAndView(viewName);
 5         
 6         //添加模型數據到 ModelAndView 中.
 7         modelAndView.addObject("time", new Date());
 8         
 9         return modelAndView;
10     }
ModelAndView

Map 及 Model

Spring MVC 在內部使用了一個org.springframework.ui.Model 接口存儲模型數據

具體步驟
Spring MVC 在調用方法前會創建一個隱含的模型對象作為模型數據的存儲容器。
如果方法的入參為 Map 或 Model 類型,Spring MVC 會將隱含模型的引用傳遞給這些入參。在方法體內,開發者可以通過這個入參對象訪問到模型中的所有數據,也可以向模型中添加新的屬性數據

    /**
     * 目標方法可以添加 Map 類型(實際上也可以是 Model 類型或 ModelMap 類型)的參數. 
     * @param map
     * @return
     */
    @RequestMapping("/testMap")
    public String testMap(Map<String, Object> map){
        System.out.println(map.getClass().getName()); 
        map.put("names", Arrays.asList("Tom", "Jerry", "Mike"));
        return SUCCESS;
    }
View Code

@SessionAttributes

若希望在多個請求之間共用某個模型屬性數據,則可以在控制器類上標注一個 @SessionAttributes, Spring MVC 將在模型中對應的屬性暫存到 HttpSession 中。

@SessionAttributes 除了可以通過屬性名指定需要放到會話中的屬性外,還可以通過模型屬性的對象類型指定哪些模型屬性需要放到會話中
  @SessionAttributes(types=User.class) 會將隱含模型中所有類型為 User.class 的屬性添加到會話中。
  @SessionAttributes(value={“user1”, “user2”})
  @SessionAttributes(types={User.class, Dept.class})
  @SessionAttributes(value={“user1”, “user2”}, types={Dept.class})

    /**
     * @SessionAttributes 除了可以通過屬性名指定需要放到會話中的屬性外(實際上使用的是 value 屬性值),
     * 還可以通過模型屬性的對象類型指定哪些模型屬性需要放到會話中(實際上使用的是 types 屬性值)
     * 
     * 注意: 該注解只能放在類的上面. 而不能修飾放方法. 
     */
    @RequestMapping("/testSessionAttributes")
    public String testSessionAttributes(Map<String, Object> map){
        User user = new User("Tom", "123456", "tom@atguigu.com", 15);
        map.put("user", user);
        map.put("school", "atguigu");
        return SUCCESS;
    }
View Code

@ModelAttribute

在方法定義上使用 @ModelAttribute 注解:Spring MVC 在調用目標處理方法前,會先逐個調用在方法級上標注了@ModelAttribute 的方法。
在方法的入參前使用@ModelAttribute 注解:

  可以從隱含對象中獲取隱含的模型數據中獲取對象,再將請求參數 綁定到對象中,再傳入入參
  將方法入參對象添加到模型中

	@ModelAttribute
	public void getUser(@RequestParam(value="id",required=false) Integer id, Map<String, Object> map){
		System.out.println("modelAttribute method");
		if(id != null){
			//模擬從數據庫中獲取對象
			User user = new User(1, "Tom", "123456", "tom@atguigu.com", 12);
			System.out.println("從數據庫中獲取一個對象: " + user);
			
			map.put("user", user);
		}
	}
	@RequestMapping("/testModelAttribute")
	public String testModelAttribute(User user){
		System.out.println("修改: " + user);
		return SUCCESS;
	}

 運行流程:

  1. 執行 @ModelAttribute 注解修飾的方法: 從數據庫中取出對象, 把對象放入到了 Map 中. 鍵為: user
  2. SpringMVC 從 Map 中取出 User 對象, 並把表單的請求參數賦給該 User 對象的對應屬性.
  3. SpringMVC 把上述對象傳入目標方法的參數.
注意: 在 @ModelAttribute 修飾的方法中, 放入到 Map 時的鍵需要和目標方法入參類型的第一個字母小寫的字符串一致!

 1         /* 源代碼分析的流程
 2      * 1. 調用 @ModelAttribute 注解修飾的方法. 實際上把 @ModelAttribute 方法中 Map 中的數據放在了 implicitModel 中.
 3      * 2. 解析請求處理器的目標參數, 實際上該目標參數來自於 WebDataBinder 對象的 target 屬性
 4      * 1). 創建 WebDataBinder 對象:
 5      * ①. 確定 objectName 屬性: 若傳入的 attrName 屬性值為 "", 則 objectName 為類名第一個字母小寫. 
 6      * *注意: attrName. 若目標方法的 POJO 屬性使用了 @ModelAttribute 來修飾, 則 attrName 值即為 @ModelAttribute 
 7      * 的 value 屬性值 
 8      * 
 9      * ②. 確定 target 屬性:
10      *     > 在 implicitModel 中查找 attrName 對應的屬性值. 若存在, ok
11      *     > *若不存在: 則驗證當前 Handler 是否使用了 @SessionAttributes 進行修飾, 若使用了, 則嘗試從 Session 中
12      * 獲取 attrName 所對應的屬性值. 若 session 中沒有對應的屬性值, 則拋出了異常. 
13      *     > 若 Handler 沒有使用 @SessionAttributes 進行修飾, 或 @SessionAttributes 中沒有使用 value 值指定的 key
14      * 和 attrName 相匹配, 則通過反射創建了 POJO 對象
15      * 
16      * 2). SpringMVC 把表單的請求參數賦給了 WebDataBinder 的 target 對應的屬性. 
17      * 3). *SpringMVC 會把 WebDataBinder 的 attrName 和 target 給到 implicitModel. 
18      * 近而傳到 request 域對象中. 
19      * 4). 把 WebDataBinder 的 target 作為參數傳遞給目標方法的入參. 
20      */        
源代碼分析流程

 SpringMVC 確定目標方法 POJO 類型入參的過程

  1. 確定一個 key:

    1). 若目標方法的 POJO 類型的參數木有使用 @ModelAttribute 作為修飾, 則 key 為 POJO 類名第一個字母的小寫
    2). 若使用了  @ModelAttribute 來修飾, 則 key 為 @ModelAttribute 注解的 value 屬性值.
  2. 在 implicitModel 中查找 key 對應的對象, 若存在, 則作為入參傳入
    1). 若在 @ModelAttribute 標記的方法中在 Map 中保存過, 且 key 和 1 確定的 key 一致, 則會獲取到.
  3. 若 implicitModel 中不存在 key 對應的對象, 則檢查當前的 Handler 是否使用 @SessionAttributes 注解修飾, 若使用了該注解, 且 @SessionAttributes 注解的 value 屬性值中包含了 key, 則會從 HttpSession 中來獲取 key 所對應的 value 值, 若存在則直接傳入到目標方法的入參中. 若不存在則將拋出異常.
  4. 若 Handler 沒有標識 @SessionAttributes 注解或 @SessionAttributes 注解的 value 值中不包含 key, 則會通過反射來創建 POJO 類型的參數, 傳入為目標方法的參數
  5. SpringMVC 會把 key 和 POJO 類型的對象保存到 implicitModel 中, 進而會保存到 request 中.

由@SessionAttributes引發的異常

如果在處理類定義處標注了@SessionAttributes(“xxx”),則嘗試從會話中獲取該屬性,並將其賦給該入參,然后再用請求消息填充該入參對象。如果在會話中找不到對應的屬性,則拋出 HttpSessionRequiredException 異常


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM