非常冷门,难用,不好理解,不建议使用。

有默认值不想被修改时,可以使用@ModelAttribute注解。

一、现在提出一个需求

我想更新数据库的三个字段:

  1. id
  2. username
  3. password

其中,id和username是需要更改的,但是password是不需要更改的。那么我们通过表单输入的就是:id和username,password是不用输入的。

提交之后,后端创建一个对象参数,也就是id=***,username=***,password=null。

一旦按照对象操作数据库,改了之后原来的password就会变成null了。这显然是我们不想看到的。

二、有如下解决办法

(1)在表单使用隐藏域

问题是,如果不想修改的是敏感信息,比如说密码,隐藏域就不能使用了。

如果不想修改的信息很多,那么就要写很多个隐藏域。

(2)在修改之前先从数据库中把对象拿出来,只更新要更改的部分,其他保持不变

似乎是个能解决问题的办法,问题是目前网站性能瓶颈往往是数据库性能导致的,这样做把原来一个简单的写操作变成了读+写操作,非常影响性能。

(3)为null不更新

假如有一天,我想把password置空,这时候我传入null就不会更新了。

以上方法都是不靠谱的。那么就需要用到我们今天这篇文章介绍的@ModelAttribute注解了。

三、实现方法

(1)首先来模拟一下以上的场景

写一个表单提交:

实现效果:

1

因为password没有被我们赋值,理所当然就是null。

我们现在希望做到:password原密码的值不能改变。

(2)怎么解决上面的问题?先写一个方法

模拟先从数据库中取得这个user对象,然后把这个对象放在map中。

返回:testMap: user [id=1, username=xie, password=123456]

1

像不像是设置了默认值一样的感觉?

前端传值过来创建user对象时,只修改了新传入的id和username值,原来的默认值password并没有改变。

这个解释并不准确,在下面进行详细解释。

(3)运行原理

现在总结一下现象:

  1. ModelAttribute start
  2. 从数据库中获取了一个对象:user [id=1, username=xie, password=123456]
  3. 修改: user [id=1, username=xie, password=123456]

也就是说,有@ModelAttribute注解的方法先执行了。

然后我们传入参数新创建的user对象中,既有新传入的参数值,也有从数据库中取出来的对象的值,是组合而成的,不存在null。

这是怎么实现的?

  1. 执行@ModelAttribute注解修饰的方法:从数据库中取出了user对象,把对象放进了map中,键为:user
  2. spring mvc从map中取出了user对象,并把表单的请求参数赋给该user对象的的对应属性,而未赋值的属性则没有改变。
  3. spring mvc把上述对象传入目标方法的参数。

我的个人理解:

  1. 一旦有请求,spring mvc就会先去找有@ModelAttribute注解修饰的方法,找到了之后,执行该方法,从数据库中取出user对象,存入map中,键值为user。
  2. spring mvc通过@RequestMapping知道了对应的方法,知道该方法将创建user对象,于是先去map中找有没有对应的对象,根据键名user,成功找到了user对象,于是把表单的请求参数赋给了user对象的对应属性。
  3. 在方法执行的时候,到了需要创建user对象的时候,把已经处理过的user对象当做参数传入目标方法中,而不是重新创建user对象。

通过这样的方式,user对象拥有了默认值,如果没有新的值传入,那么就保持默认值。

四、总结

map对象中放入的对象的键名一定要和传入参数时创建的对象名称一致。就像这里新创建的对象为user,那么map中user对象的键名也要为user。

这种用法很少见,也很容易用错,看看即可。

发表评论

电子邮件地址不会被公开。 必填项已用*标注