ModuleAndView
- 注意:ModelAndView的類型為:org.springframework.web.servlet.ModelAndView;
- 示例使用ModuleAndView處理模型資料
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
String viewName = SUCCESS;
ModelAndView modelAndView = new ModelAndView(viewName);
modelAndView.addObject("info", "你好");
return modelAndView;
}
- 使用ModuleAndView實際上會将資料使用request.setAttribute()方法儲存在請求域之中.是以可以在頁面中使用EL表達式擷取請求屬性.
- 跳轉的頁面
<body>
<h1>${info}</h1>
</body>
- 測試通路路徑:http://localhost:8080/SpringMVCModule1/testModelAndView
- 執行結果
Map處理模型資料
- 示例:
@RequestMapping("/testMap")
public String testMap(Map<String,Object> map){
map.put("time",new Date());
map.put("tom","xiemaoshu");
return SUCCESS;
}
- SpringMVC會将資料存儲到 Request範圍域之中,在頁面中可以使用 EL表達式取出資料
<h1>${time}</h1>
<h1>${tom}</h1>
- 執行效果
@SessionAttributes
- @SessionAttribute注解使用示例
//将名稱為"user"的屬性添加到Session屬性之中,也将String類型的屬性添加到Session屬性之中
@SessionAttributes(types = {User.class,String.class},value = {"user"})
@Controller
public class HelloWorld {
@RequestMapping("/testSessionAttribute")
public String testSessionAttribute(Map<String,Object> map){
User user = new User();
user.setUid(11);
user.setUname("xiemaoshu");
user.setPassword("xiemaoshu20190309xms");
map.put("user",user);
map.put("time",new Date());
return SUCCESS;
}
- 顯示頁面
<h1>${user}</h1>
<h1>${time}</h1>
- 效果
@ModuleAttribute注解
遇到的問題?
- 如果此時要進行對資料庫中的一個資料進行修改操作,但是要求:某一個字段的内容不允許被修改.例如:修改一個使用者的資料"User",使用者資料中的建立時間與密碼資訊是不允許被修改的.如果從表單中直接收要修改的資料,那麼在操作方法中往往需要提供一個User類執行個體化對象,那麼這個User類執行個體化對象中,"建立時間"和"密碼"字段隻能夠是"null"空,如何能夠放置出現null的情況?
實作的思路有兩種:
-
由表單填入修改資料,但是不提供"建立時間"和"密碼"的修改操作,将使用者的建立時間和密碼資訊由隐藏域儲存起來,接着再調用方法中new一個執行個體化對象,将修改資料儲存到新的執行個體化對象之中.
- 這樣做有一個缺點就是:重要的資訊不适合放在隐藏域中,況且,如果不能夠修改的字段比較多的話,需要設定多個隐藏域.
- 先從資料庫中讀取出要修改的使用者資訊,而後隻提供要修改的資料操作
使用@ModuleAttribute解決
- 模拟一個資料修改操作
- 修改頁面表單
<body>
<%--
模拟一個資料修改操作
原始資料為:
uid=1
password=12345
uname=xiemaoshu
--%>
<form method="post" action="testModelAttribute">
<div>
使用者id:<input type="text" name="uid" id="uid" value="1"/>
</div>
<div>
使用者名稱:<input type="text" name="uname" id="uname" value="xiemaoshu"/>
</div>
<div>
<input type="submit" value="送出"/>
</div>
</form>
</body>
- 進行修改操作的方法
@ModelAttribute//SpringMVC在執行映射請求方法之前,會先調用帶有@ModelAttribute 注解的方法
public void getUser(@RequestParam(value = "uid",required = false) Integer uid,Map<String,Object> map){
//模拟從資料庫中擷取使用者資料
User user =new User();
user.setUid(uid);
user.setUname("xiemaoshu");
user.setPassword("12345");
map.put("user",user);//将user資料儲存到request請求域之中
System.out.println("擷取uid = "+uid+" 的使用者資料"+user);
}
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user){
System.out.println("執行修改操作:"+user);
return SUCCESS;
}
- 測試結果
- 背景輸出
- 可以發現password不為null,這是因為在執行請求方法前,會先執行"@ModelAttribute"注解的方法
@ModelAttribute運作原理
- 運作流程:
- 執行@ModelAttribute注解修飾的方法:從資料庫中取出資料,将資料放入到了Map中,鍵為:user
- SpringMVC從map中取出User對象,并把表單的請求參數付給該User對象的對應屬性,
- SpringMVC把上述對象傳入目标方法的參數.
- 注意:在ModelAttribute修飾的方法中,放入到Map時的鍵需要和目标方法入參類型的第一個字母小寫的字元串一緻
@ModelAttribute注解之源碼分析
- 調用@ModelAttribute注解修飾的方法,實際上把@ModelAttribute方法中Map中的資料放在了implicitModel中
- 解析請求處理器的目标參數,實際上該目标來自于WebDataBinder對象的target屬性
- 建立WebDataBinder對象:
- 确定objectName屬性:若傳入的arrtName屬性值為空字元串,則objctName為類名第一個字母小寫.(=乳溝目标方法的POJO回資訊使用了@ModelAttribute來修飾,則attrName值即為@ModelAttribute的value屬性值==)
- 确定target屬性:
- 在implicitModel中查找attriName對應的屬性值.
- 若不存在:則驗證目前的Hiddler是否使用了@SessionAttribute進行修飾,若使用了,則嘗試從Session中擷取arrtName所對應的屬性值,若session中沒有對應的屬性值,則抛出異常.
- 若Handler沒有使用@SessionAttribute進行修飾,或@SessionAttributes中沒有使用value值指定的key和attrName相比對,則通過反射建立了POJO對象.
- SpringMVC把表單中請求參數賦給WebDataBinder的target屬性.
- SpringMBC會把WebDataBinder的attrName和target給到implicitModel
- 把webDataBinder的target作為參數傳遞給目标方法的入參.
- 在"@ModelAttribute"注解的方法中和請求的方法中打上斷點