目录
一、@ModelAttribute注解详解之使用场景
1.1 常用场景分析
1.2 有问题的做法
1.2.1 传统做法
1.2.2 传统做法实现代码
1.3 正确做法
1.3.1 正确做法图示
1.3.2 实现代码
1.4 @ModelAtrribute注解的执行流程
二、 @ModelAtrribute源代码分析
三、 springMVC 确定目标方法 POJO 类型入参的过程
四、解决@ModelAtrribute中,map的键与执行目标方法的参数名不一致
@ModelAttribute注释方法 , 在Spring mvc中,注解@ModelAttribute是一个非常常用的注解,其功能主要在两方面:
1、运用在参数上,会将客户端传递过来的参数按名称注入到指定对象中,并且会将这个对象自动加入ModelMap中,便于View层使用;
2、运用在方法上,会在每一个@RequestMapping标注的方法前执行,如果有返回值,则自动将该返回值加入到ModelMap中;
@ModelAttribute等价于上一章的 model.addAttribute("attributeName", abc);
表有几个字段,只修改符合条件的一条记录中的字段,其它一个字段不能修改。如密码不能修改,id是自增的
传统一般做法,如图:
new一个对象,然后表单参数传给这个对象,再执行update命令更新整个对象,其中两个字段有值,但会出现一个问题,其中一个字段没斌值,没有被更新的字段值会为空!
先建立相关代码 src/main/java/com.hualinux.springmvc.entities/User2.java代码
package com.hualinux.srpingmvc.entities; public class User2 { private Integer id; private String username; private String password; private String email; private int age; public User2() { } public User2(Integer id, String username, String password, String email, int age) { this.id = id; this.username = username; this.password = password; this.email = email; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User2{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", email='" + email + '\'' + ", age=" + age + '}'; } }在src/main/java/com.hualinux.srpingmvc.handers/SpringMVCTest.java,添加如下代码
先把 @SessionAttributes注解掉
@RequestMapping("/springmvc/testModelAtrribute2") public String testModelAtrribute2(User2 user2){ System.out.println("修改:"+user2); return "ok"; }打开web/index.jsp,在其页面的<body></body>标签中添加如下代码:
<div> <%-- 模拟修改操作: 1. 原始数据为: 1,Tom,123456,tom@hualinux.com,12 2. 密码不能被修改 3. 表单回显,模拟操作直接在表单填写对应的属性值 --%> <form action="springmvc/testModelAtrribute2" method="post"> <input type="hidden" name="id" value="1"> username:<input type="text" name="username" value="Tom" /><br> email:<input type="text" name="email" value="tom@hualinux.com" /><br> age:<input type="text" name="age" value="12" /><br> <input type="submit" value="Submit" /> </form> </div>运行tomcat,idea会自动打开主页点,输入如下内容:
看到返回“ok,访问成功!”时,再看idea最下方的日志输出如下:
修改:User2{id=1, username='Tom', password='null', email='tom@hualinux.com', age=12}
上面发现密码是空,原来是123456的,你现在把它变成空了,肯定不行,不符合需求!
在src/main/java/com.hualinux.srpingmvc.handers/SpringMVCTest.java,添加多一段代码,如下:
//有@ModelAtrribute注解的方法,会在每个目标方法执行前被springMVC调用 @ModelAttribute public void getUser(@RequestParam(value = "id",required = false) Integer id, Map<String,Object> map ){ if (id != null){ //模拟从数据库中获取对象,这里为了方便就没有设置连接数据库 User2 user2 = new User2(1,"li","123456","li@hualinux.com",20); System.out.println("从数据库中获取一个对象:"+user2); //把信息放在map中, map.put("user2",user2); } }注意:在@ModelAttribute 修饰方法中,放入到Map时的键需要和目标方法入参参数的第一个字母小字的字符串一致。
这样总的代码有2段,如下:
再次运行一次看一下效果
看到返回“ok,访问成功!”时,再看idea最下方的日志输出如下:
发现名字、email、年龄都被修改了,密码没变,正是我们想要的效果
1.执行@ModelAtrribute注解修饰的方法:从数据库中取出对象,并把对象放到了Map中,键为user
2.springMVC从Map集合中取出User对象,并把表单的请求参数赋值给user对象相应的属性
3.springMVC把上述对象传入目标方法的参数
4.这个user对象是存在request中,如果jsp表单中有对应的字段,还会自动填充表单
注意:在@ModelAtrribute修饰的方法中,放入Map时的键要和目标方法的参数名一致
SpringMVC 确定目标方法P0J0类型入参的过程 1. 确定一个key: 1)若目标方法的P0J0类型的参数木有使用@ModelAttribute作为修饰,则key为P0J0类名第一个字母的小写 2)若使用了@ModelAttribute 来修饰,则key为@ModelAttribute注解的value属性值。
2.在implicitModel 中查找key对应的对象,若存在,则作为入参传入。 若在@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和P0J0类型的对象保存到implicitModel中,进而会保存到request中。
解决@ModelAtrribute注解中,map集合的键与执行目标方法的参数名不一致的情况
其实我们可以在目标方法里面的参数中,定义一个@ModelAtrribute注解,并把其值指定为@ModelAtrribute注解修饰的方法中的map的键
src/main/java/com.hualinux.srpingmvc.handers/SpringMVCTest.java,相关的代码进行了一下修改
运行tomcat,idea会自动打开主页点,输入如下内容:
看到返回“ok,访问成功!”时,再看idea最下方的日志输出如下:
修改后的结果和没修改前的结果是一样的。