1、@ModelAttribute注解
@ModelAttribute主要有三个用途,对方法进行注解,对参数进行注解,还有@ModelAttribute和@RequestMapping一起对方法进行注解。
(1) 对方法进行注解
@ModelAttribute对方法进行注解,有两个作用,一是在调用@RequestMapping注解的方法之前,先调用@ModelAttribute注解的方法,二是在@ModelAttribute注解的方法中,所有Map的对象都放入ImpliciteModel中,key就是Map的key。在后面讲解POJO传参的过程中,会讲解ImpliciteModel的作用。测试代码如下:
两个POJO代码如下:、
User.java
1 package com.hxg.springmvc.entries; 2 3 public class User { 4 private String username; 5 private String password; 6 private int id; 7 8 public int getId() { 9 return id; 10 } 11 12 @Override 13 public String toString() { 14 return "User [username=" + username + ", password=" + password 15 + ", id=" + id + "]"; 16 } 17 18 public void setId(int id) { 19 this.id = id; 20 } 21 22 public String getUsername() { 23 return username; 24 } 25 26 public void setUsername(String username) { 27 this.username = username; 28 } 29 30 public String getPassword() { 31 return password; 32 } 33 34 public void setPassword(String password) { 35 this.password = password; 36 } 37 38 public User(int id, String username, String password) { 39 super(); 40 this.username = username; 41 this.password = password; 42 this.id = id; 43 } 44 45 public User() { 46 super(); 47 } 48 49 }
Cat.java
1 package com.hxg.springmvc.entries; 2 3 public class Cat { 4 private int speed; 5 6 public int getSpeed() { 7 return speed; 8 } 9 10 public void setSpeed(int speed) { 11 this.speed = speed; 12 } 13 14 }
Controller的代码如下
1 package com.hxg.springmvc.web.controller; 2 3 import java.util.Map; 4 5 import org.springframework.stereotype.Controller; 6 import org.springframework.web.bind.annotation.ModelAttribute; 7 import org.springframework.web.bind.annotation.RequestMapping; 8 import org.springframework.web.bind.annotation.SessionAttributes; 9 10 import com.hxg.springmvc.entries.Cat; 11 import com.hxg.springmvc.entries.User; 12 13 @Controller 14 public class HandlerController { 15 16 @RequestMapping("/hello") 17 public String hello(@ModelAttribute("users")User user, Map<String, Object> map, Cat cat, String password) 18 { 19 cat.setSpeed(100); 20 System.out.println(password); 21 return "hello"; 22 } 23 24 @ModelAttribute 25 public String preUser(Cat cat, User user, Map<String, Object> map, String username) 26 { 27 System.out.println(username); 28 cat.setSpeed(110); 29 user.setId(1); 30 User user1 = new User(2, "username1", "password1"); 31 map.put("users", user1); 32 return "abc"; 33 } 34 35 36 37 }
提交表单的部分代码
1 <form action="hello.do" method="post"> 2 <input name="username" type="text"/> 3 <input name="password" type="text"/> 4 <input type="submit" value="submit" > 5 </form>
页面显示代码:
1 <body> 2 user: 3 ${user.username } 4 ${user.password } 5 ${user.id } 6 <br><br> 7 users: 8 ${users.username } 9 ${users.password } 10 ${users.id } 11 <br><br> 12 string: 13 ${string} 14 <br><br> 15 cat: 16 ${cat.speed } 17 <br><br> 18 username: 19 ${username } 20 <br><br> 21 password: 22 ${password } 23 </body>
在表单中输入username, password,页面显示的结果如下:
控制台中输出:username password
从结果可以看出:@ModelAttribute注解的方法在@RequestMapping注解的方法之前执行,并且preUser方法中,一共有四个对象放入map中,相当于:
map.put("cat", cat)、map.put("user", user)、map.put("users", user1)和map.put("string", "abc");
POJO在传参的过程中,springmvc会默认的把POJO放入到map中,其中键值就是类名的第一个字母小写。在@ModelAttribute注解的方法里,POJO放入到Map的同时,也放入ImpliciteModel中, 比如上面代码中的user和cat。@ModelAttribute注解的方法里,返回类型不是void,则返回的值也会被放到Map中,其中键值为返回类型的第一个字母小写。比如上述代码中,返回的"abc",就会被放入到Map中,相当于map.put("string", "abc")。
在执行@ModelAttribute注解的方法里,表单的数据会被当作参数传到@ModelAttribute注解的方法,和@RequestMapping注解的方法传参是一样的。
(2) @ModelAttribute对参数进行注解
比如上面的代码,@ModelAttribute("users")User user。在传参的过程中,首先检查ImpliciteModel有没有键值为users,有的话,直接从ImpliciteModel中取出该对象,然后在把表单传过来的数据赋值到该对象中,最后把该对象当作参数传入到@RequestMapping注解方法里,也就是hello方法。当检查到键值的话,并不会创建新的对象,而是直接从ImpliciteModel直接取出来。
(3) @ModelAttribute和@RequestMapping一起对方法进行注解
@ModelAttribute和@RequestMapping对方法进行注解时,其中返回类型被到Map中,并不会被当作视图的路径进行解析。把controller代码改变成如下:
1 package com.hxg.springmvc.web.controller; 2 3 import java.util.Map; 4 5 import org.springframework.stereotype.Controller; 6 import org.springframework.web.bind.annotation.ModelAttribute; 7 import org.springframework.web.bind.annotation.RequestMapping; 8 import org.springframework.web.bind.annotation.SessionAttributes; 9 10 import com.hxg.springmvc.entries.Cat; 11 import com.hxg.springmvc.entries.User; 12 13 @Controller 14 public class HandlerController { 15 16 @ModelAttribute 17 @RequestMapping("/hello") 18 public String hello(@ModelAttribute("users")User user, Map<String, Object> map, Cat cat, String password) 19 { 20 cat.setSpeed(100); 21 System.out.println(password); 22 return "bbbbb"; 23 } 24 25 @ModelAttribute 26 public String preUser(Cat cat, User user, Map<String, Object> map, String username) 27 { 28 System.out.println(username); 29 cat.setSpeed(110); 30 user.setId(1); 31 User user1 = new User(2, "username1", "password1"); 32 map.put("users", user1); 33 return "abc"; 34 } 35 36 37 38 }
其中返回的视图路径就是@RequestMapping("/hello")中的hello,显示结果如下:
从结果中,bac变为了bbbbb,主要是因为返回值会被放入到map,键值为返回类型第一个字母的小写,原来的map.put("string", "abc")被覆盖掉,变成map.put("string", "bbbbb")。
2、POJO传参的过程
POJO传参的过程中,先检查ImpliciteModel中是否有相对应的键值,有的话就把该键值的对象取出来,把表单传过来的数据传到该对象,然后把该对象作为参数传到目标方法中,也就是@RequestMapping注解的方法中。在ImpliciteModel没有相对应的键值,假如controller用SessionAttribute进行注解,则就会在Session attribute查找相对应的key,假如找到了key,却没有对象,则会报异常。在ImpliciteModel和SessionAttribute都没有查找到key,才会创建新的对象,把表单传过来的数据赋值给新的对象,最后把新的对象作为参数传到目标方法中。
以下是报异常的代码
1 package com.hxg.springmvc.web.controller; 2 3 import java.util.Map; 4 5 import org.springframework.stereotype.Controller; 6 import org.springframework.web.bind.annotation.ModelAttribute; 7 import org.springframework.web.bind.annotation.RequestMapping; 8 import org.springframework.web.bind.annotation.SessionAttributes; 9 10 import com.hxg.springmvc.entries.Cat; 11 import com.hxg.springmvc.entries.User; 12 13 @SessionAttributes("user") 14 @Controller 15 public class HandlerController { 16 17 @ModelAttribute 18 @RequestMapping("/hello") 19 public String hello(@ModelAttribute User user, Map<String, Object> map, Cat cat, String password) 20 { 21 cat.setSpeed(100); 22 System.out.println(password); 23 return "bbbbb"; 24 } 25 }
会报如下异常:
只要把@SessionAttributes("user")改成@SessionAttributes("users")就可以消去异常,或者把public String hello(@ModelAttribute User user, Map<String, Object> map, Cat cat, String password)中的@ModelAttribute 去掉,只有用@ModelAttribute注解参数,才会从session attribute中查找相对应的key。