Spring MVC 中的 @ModelAttribute 注解以及源码的相关分析

为了更形象地引出 @ModelAttribute注解:
下面来仔细看这两幅图:
需求:对数据库中的表单信息进行修改(例如表单中有三项数据)
现在只需更新其中的两项数据,第三项数据不变(即与数据库中的信息保持一致)

1:通过new一个新对象实现更新操作:
结果:第三项数据为null;
在这里插入图片描述
2.从数据库中取出数据,在原来的基础上进行更新操作:
结果:完美的实现了需求;
在这里插入图片描述
下面来看代码:

表单信息:

  <!-- 模拟和修改操作 
	   1.原始数据:1 , Tom , 12 ,[email protected]
	   2.密码不能被修改。
	   3.表单回显,模拟操作在表单填写对应的属性值。
	   -->
	<form action="springmvc/testModelAttribute" 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="[email protected]"/>
		<br>
		age:<input type="text" name="age" value="12"/>
		<br>
		<input type="submit" value="Submit"/>	
	</form>

首先是上图1方式进行的更新:

@RequestMapping("/testModelAttribute")
	public String testModelAttribute(User user) {
		System.out.println("修改 :" + user);		
		return SUCCESS;
	}

提交更改操作:
在这里插入图片描述
结果返回:
(注意看password的值!!虽然age变化了,但密码仍为null)

修改 :User [id=1, username=Tom, password=null, [email protected], age=15]

其次是上图2方式进行的更新:

在上述代码的基础上增加一个用@ModelAttribute注解标注的类

/*
* 有 @ModelAttribute 标记的方法 ,会在每个目标方法执行之前被Spring MVC调用!
* @ModelAttribute 注解也可以来修饰目标方法POJO类型的入参,其中value属性值有如下作用:
* 1).Spring MVC会使用value属性值在implicitModel中查找对应的对象,若存在则会直接传入到目标方法的入参中。
* 2).Spring MVC会以value为key值,POJO类型的对象为value,存入到request中。
*/

	@ModelAttribute
	public void getUser(@RequestParam(value="id",required = false) Integer id,
			Map<String, Object> map) {
		System.out.println("ModelAttribute method" );	
		if( id!=null) {
			//模拟从数据库中获取对象
			User user = new User(1, "Tom", "123456" , "[email protected]", 12);
			System.out.println("从数据库中获取一个对象 :" + user);		
			map.put("user", user);
		}	
	}

结果返回:
(注意看前后的对象中password值!!以及age也成功更新!)

ModelAttribute method
从数据库中获取一个对象 :User [id=1, username=Tom, password=123456, [email protected], age=12]
修改 :User [id=1, username=Tom, password=123456, [email protected], age=15]

@ModelAttribute总结:

/*
* 运行流程:
* 1.执行 @ModelAttribute 注解修饰的方法:从数据库中取出对象,把对象放入到了Map中,键为:user;
* 2.SpringMVC 从 Map中取出User对象,并把表单中请求参数赋给该User对象的对应属性;
* 3.Spring MVC把上述对象传入目标方法的参数;
*/

注意:在@ModelAttribute 注解修饰的方法中,放入到Map时的键需要和目标方法入参类型的第一个字母小写的字符串一致!

/*
* SpringMVC确定目标方法POJO类型入参的过程:
*
* 1.确定一个key:
*
* 1).若目标方法的POJO类型的参数没有使用@ModelAttribute 作为修饰,则key为POJO类名第一个字母的小写
*
* 2).若使用了@ModelAttribute 来修饰,则key为@ModelAttribute 注解的value值
*
* 2.在implicitModel查找key对应的对象,若存在,则作为入参传入;
*
* 1).若在@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和 POJO类型的对象保存到implicitModel 中,进而保存到request中。
*
* /

@ModelAttribute源码分析:

 * 1.调用@ModelAttribute注解修饰的方法。实际上把@ModelAttribute方法中Map中的数据放在了implicitModel中。
 * 2.解析请求处理器的目标参数,实际上该目标参数来自于WebDataBinder对象的target属性
 *  
 *   1). 创建 WebDataBinder 对象
 *   
 *         1.确定objectName属性:
 *         若传入的attrName属性值为"",则objectName为类名第一个字母小写。
 *         *注意:attrName: 若目标方法的POJO属性使用了@ModelAttribute来修饰,则attrName值为@ModelAttribute的value属性值
 *         例如:public String testModelAttribute(@ModelAttribute("user") User user) {}
 *         
 *         2.确定target属性:
 *          》.在 implicitModel 中查找 attrName对应的属性值。若存在,ok;
 *          》*若不存在:则验证当前Handler是否使用了 @SessionAttributes 进行修饰,若使用了,则尝试从Session中获取attrName所对应的属性值。
 *           若session中没有对应的属性值,则抛出了异常;
 *         》若Handler没有使用@SessionAttributes 进行修饰,或者@SessionAttributes中没有使用value值指定的key
 *           和attrName 相匹配,则通过反射创建POJO对象
 *   
 *   2). SpringMVC把表单的请求参数赋给了WebDataBinder的target对应的属性。
 *   3). SpringMVC会把WebDataBinder的attrName 和target 给到 implicitModel.进而传到 request域对象中;
 *   4). 把 WebDataBinder 的target 作为参数传递给目标方法的入参;    
 */
发布了11 篇原创文章 · 获赞 0 · 访问量 103

猜你喜欢

转载自blog.csdn.net/qq_43395576/article/details/104485875
今日推荐