[原創]SpringMVC中@ModelAttribute用法小結
顧名思義,@ModelAttribute註釋可以爲模型添加屬性。@ModelAttribute通常是和@RequestMapping配合使用的,@ModelAttribute和@RequestMapping註釋位置有所不同,其用法也有區別。
1. ModelAttribute和RequestMapping分開註釋不同方法
先來一張項目結構圖,User類是POJO類,MyController實現對請求的處理,index.jsp是登陸頁面,result.jsp是處理結果頁面:
User類如下:
package matest;
public class User {
private String loginname;
private String password;
public User() {
super();
}
public User(String loginname, String password) {
this.loginname = loginname;
this.password = password;
}
public String getLoginname() {
return loginname;
}
public void setLoginname(String loginname) {
this.loginname = loginname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return this.getLoginname() + this.getPassword();
}
}
result.jsp用來顯示MyController的處理結果:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
你好${user.loginname}<br>
</body>
</html>
下面先看MyController類中,只有@RequestMapping存在的情況:
@Controller
public class MyController {
@RequestMapping("/login")
public String skrWu() {
return "result";
}
}
當向後端發送/login請求時,將會尋找被@ReuqestMapping標記的方法,進行匹配。這種情況下,會直接返回result.jsp視圖。
登錄結果:
可以看到,因爲我們沒有進行任何處理,所以沒有打印user的loginname信息,這是理所當然的。
現在,輪到@ModelAttribute登場了,我們爲MyController添加一個用@ModelAttribute註釋的test()方法,來接收前端傳來的登錄名和密碼信息,生成和保存User對象。
@Controller
public class MyController {
@ModelAttribute
public User test(@RequestParam("loginname") String loginname, @RequestParam("password") String password) {
User user = new User();
user.setLoginname(loginname);
user.setPassword(password);
return user;
}
@RequestMapping("/login")
public String skrWu() {
return "result";
}
}
再次運行,
運行結果:
這次就有user的loginname信息了。原因何在呢?
原來,在執行被@RequestMapping標註的方法前,SpringMVC會先依次執行被@ModelAttribute標註的方法。在這個例子裏,先運行的test() 方法接收了前端傳來的登錄名和密碼信息,並將其值傳給了新建的user對象。在test() 方法執行結束後,user對象已經存儲在了model當中。之後運行skrWu() 方法,跳轉到result.jsp,因此可以在result.jsp中訪問user對象了。如果test() 方法沒有被@ModelAttribute標註,是無法得到運行的。
在這種默認寫法(@ModelAttribute)下,model中user的屬性名就是test()方法的返回類型User的小寫。如果想要自定義模型中user的屬性名,可以採用@ModelAttribute("屬性名");或者model.addAttribute("屬性名", 屬性值);兩種方法。如下:
@ModelAttribute("userWu")
public User test(@RequestParam("loginname") String loginname, @RequestParam("password") String password,Model model) {
User user = new User();
user.setLoginname(loginname);
user.setPassword(password);
return user;
}
或者
@ModelAttribute
public void test(@RequestParam("loginname") String loginname, @RequestParam("password") String password,Model model) {
User user = new User();
user.setLoginname(loginname);
user.setPassword(password);
model.addAttribute("userWu", user);
}
這樣,在result.jsp中就可以通過${userWu.loginname}訪問登錄名了。
2.@ModelAttribute出現在@RequestMapping註釋的方法的參數裏
改寫MyController類如下:
@Controller
public class MyController {
@RequestMapping("/login")
public String skrWu(@ModelAttribute("user1") User user) {
return "result";
}
}
改寫result.jsp如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
你好${user1.loginname}<br>
${user1.password}<br>
</body>
</html>
通過前端頁面或者URL發送請求:
或:
結果如下:
可見參數已經傳給了user1對象。
那麼總結一下,當[@ModelAttribute("屬性名") 類型 對象 ]出現在方法參數中時,它首先會試圖自動將form表單或URL裏的屬性傳給對象,這時甚至不用顯式使用set方法,只要欲傳遞的屬性名(loginname,password)在POJO類和前端表單name中對應即可。
3.@ModelAttribute和@RequestMapping同時註釋同一個方法
輪到freeStyle出場了。
新建MyControllerV2類:
@Controller
public class MyControllerV2 {
@ModelAttribute("user")
@RequestMapping("/freeStyle")
public String skrWu() {
//freeStyle:將要跳轉的視圖名
//user(屬性名)=result(屬性值)
return "result";
}
}
前端對應/freeStyle請求的代碼塊片段爲
<a href="freeStyle" >
<button>點我跳轉到freeStyle!</button>
</a>
新建freeStyle.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
${user}
</body>
</html>
點擊下圖按鈕,
結果爲:
下面分析一下執行過程:
當@ModelAttribute和@RequestMapping同時註釋skrWu()方法時,此時方法的返回值不再代表視圖名,取而代之的是@RequestMapping的value值成爲了視圖名。而@ModelAttribute的value值代表屬性名,方法返回值此時代表ModelAttribute屬性名的屬性值。和前面兩種情況區別較大。
4.@ModelAttribute出現在@RequestMapping修飾的方法的返回值之前
可能很多人已經暈了,寫成代碼大概是這個樣子:
@RequestMapping("/請求")
public @ModelAttribute("屬性名") 返回值 方法名(參數名){方法體}
至於這樣寫的作用,還是看例子吧。
重寫MyControllerV2類,如下:
@Controller
public class MyControllerV2 {
@RequestMapping("/freeStyle")
public @ModelAttribute("wuli") User test(@RequestParam("loginname") String loginname,
@RequestParam("password") String password) {
User user = new User();
user.setLoginname(loginname);
user.setPassword(password);
return user;
}
}
前端/freeStyle請求對應的代碼塊如下:
<form action="freeStyle" method="post">
<table>
<tr>
<td><label>登錄名:</label></td>
<td><input type="text" id="logins" name="loginname" ></td>
</tr>
<tr>
<td><label>密碼:</label></td>
<td><input type="text" id="password" name="password" ></td>
</tr>
<tr>
<td><input type="submit" id="submit" value="登錄" ></td>
</tr>
</table>
</form>
freeStyle.jsp如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
你好,${wuli.loginname}
</body>
</html>
登錄。。
登錄結果:
分析:@RequestMapping的行爲和第3種情況類似,方法返回值不再代表視圖名(畢竟類型也不同了),取而代之的是@RequestMapping的value值代表了視圖名,在這個例子裏爲freeStyle.jsp。@ModelAttribute("屬性名")會把方法返回值存入model,相當於執行了 model.setAttribute("wuli",user);
不過值得注意的是,這種情況下,SpringMVC並不會試圖自動將前端傳入的參數賦給@ModelAttribute修飾的對象,需要手動賦值。因此,如果註釋掉
//user.setLoginname(loginname);
//user.setPassword(password);
就無法獲得對象wuli的屬性值了。