Java 在基于SpringMVC的webapp中,如何判断用户是否提交了具有更改值的表单?
在SpringMVCwebapp中,我有一个表单和一个相应的控制器。在控制器中,我需要知道用户是否更改了表单中的任何值,以便知道是否更新数据库中状态表中的“changed_on”列 我不想知道哪个字段被更改了,我会保存用户的数据。但是如果用户在提交之前更改了-> B,然后返回到A,我不想考虑这一变化。我只想在用户实际更改数据时更新日期/时间列,因为我需要在以后知道用户上次更改数据的时间 实现这一目标的最佳方式是什么?在后端还是在前端做比较好?这似乎是一个非常普遍的问题:如何判断用户是否正在更改表单上的数据 我想出了一些可能的解决办法。我的表单字段是布尔、整数、字符串和枚举 前端解决方案Java 在基于SpringMVC的webapp中,如何判断用户是否提交了具有更改值的表单?,java,forms,spring-mvc,Java,Forms,Spring Mvc,在SpringMVCwebapp中,我有一个表单和一个相应的控制器。在控制器中,我需要知道用户是否更改了表单中的任何值,以便知道是否更新数据库中状态表中的“changed_on”列 我不想知道哪个字段被更改了,我会保存用户的数据。但是如果用户在提交之前更改了-> B,然后返回到A,我不想考虑这一变化。我只想在用户实际更改数据时更新日期/时间列,因为我需要在以后知道用户上次更改数据的时间 实现这一目标的最佳方式是什么?在后端还是在前端做比较好?这似乎是一个非常普遍的问题:如何判断用户是否正在更改表
onChange
或onBlur
侦听器设置隐藏表单字段$(“form:input”).change()
的jQuery,并使用.data()
将changed
值设置为true
@InitBinder(“formName”)
),基于我感兴趣的所有字段重写hashCode()
。因为我没有在任何集合中使用我的表单类,也没有传递到Hibernate,所以我不认为这会产生任何不良的副作用。下面是一个使用Guava的实现:
@Override
public int hashCode() {
return Objects.hashCode(this.field1, this.field2, etc.);
}
然后,我可以将旧表单对象(在get()
方法中创建)与WebDataBinder
根据提交的表单值创建的新表单对象进行比较。如果哈希值不同,则用户更改了某些内容
这种方法的问题是,如何保留旧的表单对象?有没有办法把它塞进页面的ModelAndView
,这样就可以从文章中保存下来?或者我可以在我的doPost()
方法中重新创建它,方法是重新加载基于数据库的持久实体吗?如果Hibernate缓存了我的实体,那么在保留任何新的更改之前,重新创建原始表单对象应该非常快hashCode()
方法中。下面是一个实现:
public static boolean hasFormChanged(Object form1, Object form2) {
return HashCodeBuilder.reflectionHashCode(form1) != HashCodeBuilder.reflectionHashCode(form2);
}
现在,我知道反思是缓慢的;在我的测试中,大约比上面的Objects.hashCode()
方法慢8-12倍。然而,我只有4个表单字段,在本地机器上的测试中,基于反射的方法每次调用大约需要3.5微秒。反射的另一个缺点是,我们需要注意向表单类(或其父类)添加任何我们不想包含在比较中的新实例变量对于前端解决方案,您可以实现更通用的示例,它可以应用于任何页面。在页面加载时,迭代
表单
元素,然后迭代表单的每个字段并保存其名称和值
比如说,
[“form1”、{field1:“value1”}、{field2:“value2”}]
等
在提交之前,您可以检查新表单值是否等于旧表单值,并添加附加属性“changed”
每个前端解决方案都是丑陋的。当然,最好是在服务器端实现
您可以将旧对象存储在httpSession中,也可以再次请求它(注意hibernate默认情况下不使用缓存)。使用hashCode
而不是equals
有什么意义?当不同的对象返回相同的哈希代码时,发生冲突的可能性很小
最直接的方法是,第二次从Db请求对象,并使用equals将它们与重写
equals()
进行比较,我更担心会弄乱依赖于对象相等性的东西。也就是说,如果Spring获取了我的表单对象的多个实例,并且依赖equals()
来比较它们,我将改变这种行为。而对于hashCode()
,我并没有以一种可以想象的方式重写任何行为,这可能会搞乱任何事情。我只是对得到假阳性/假阴性的可能性感到满意,我认为这是非常非常小的。你不应该担心这一点(不可能破坏任何东西)。毕竟,如果您仍然担心,只需创建一个新方法,该方法将逐个字段比较您的对象,而不会覆盖任何内容。我最终为此使用了一个后端解决方案:equalbuilder\reflectionEquals()
。它的性能比使用EqualsBuilder
硬编码每个字段慢8-10倍,但速度仍然非常快,可能会增加几微秒的请求时间。它还使我不必在所有15个表单类中实现equals()
,并在添加、重命名或删除表单字段时使它们保持最新。谢谢你的帮助。