目录
一、@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,在其页面的
标签中添加如下代码:
<%--
模拟修改操作:
1. 原始数据为: 1,Tom,123456,[email protected],12
2. 密码不能被修改
3. 表单回显,模拟操作直接在表单填写对应的属性值
--%>
运行tomcat,idea会自动打开主页点,输入如下内容:
看到返回“ok,访问成功!”时,再看idea最下方的日志输出如下:
修改:User2{id=1, username='Tom', password='null', email='[email protected]', 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 map ){
if (id != null){
//模拟从数据库中获取对象,这里为了方便就没有设置连接数据库
User2 user2 = new User2(1,"li","123456","[email protected]",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时的键要和目标方法的参数名一致
/*
* 源代码分析流程:
* 1. 调用 @ModelAtrribute 注解修饰的方法,实际上是把 @ModelAtrribute 方法中的Map数据放到了implicitModel中。
* 2.解析请求处理器的目标参数,实际上该目标参数来自于 WebDataBinder 对象的target属性
* 1).创建WebDateBinder对象:
* ①.确定objectName属性:若传入的attrName属性为"",则objectName为类名第一一些人字母小写
* *注意:attrName.若目标方法的POJO属性使用了 @ModelAttribute 来修饰,则attrName值即为 @ModelAttribute的value 属性值
* ②确定target属性:
* >在implicitModel中查找attrName对应的属性值。若存在,ok
* >*若不存在:则验证当前的Hander是否使用了 @SessionAttributes 进行修饰,若使用了,则尝试从Session中获取
* attrName所对应的属性值.若seesion中没有对应的属性值,则抛出异常.
* >若Handler没有使用 @SessionAttributes 进行修改,或 @SessionAttributes 中没有使用value 值指定的
* key和attrName相匹配,则通过反射创建了 POJO 对象
*
* 2). SpringMVC 把表单的请求参数赋值为了 WebDateBinder 的 target 对应的属性.
* 3). *SpringMVC 会把 WebDateBinder 的 attrName 和 target 给 implicitModel
* 4). 把 WebDateBinder 的 target 作为参数传递给目标方法
*
* */
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最下方的日志输出如下:
修改后的结果和没修改前的结果是一样的。