繁体   English   中英

如何判断用户是否在基于Spring MVC的Web应用程序中提交具有更改值的表单?

[英]How to tell if user is submitting a form with changed values, in a Spring MVC-based webapp?

在Spring MVC Web应用程序中,我有一个表单和一个相应的控制器。 在控制器中,我需要知道用户是否更改了表单中的任何值,以便知道是否要更新数据库状态表中的“ changed_on”列。

我不在乎知道哪个字段发生了更改,无论如何我都会保存用户的数据。 但是,如果用户在提交之前先将A-> B更改为A,然后又返回A,则我不想考虑该更改。 我只想在用户实际更改数据时更新日期/时间列,因为稍后需要知道用户最后一次更改数据的时间。

实现此目标的最佳方法是什么? 最好在后端还是在前端? 这似乎是一个非常普遍的问题:如何判断用户是否正在更改表单上的数据。

我已经提出了一些潜在的解决方案。 我的表单字段是布尔值,整数,字符串和枚举。

前端解决方案

  1. 使用Javascript中的onChangeonBlur侦听器设置隐藏的表单字段。
  2. 使用带有$("form :input").change()的jQuery 回调函数 ,并使用.data()changed值设置为true

后端解决方案

  1. 在Web表单绑定到的表单类中(通过我的控制器中的@InitBinder("formName") ),基于我想监视更改的所有字段来覆盖hashCode() 因为我没有在任何集合中使用表单类,也没有将其传递给Hibernate,所以我没有想到这样做会有任何不良影响。 这是一个使用Guava的实现:

     @Override public int hashCode() { return Objects.hashCode(this.field1, this.field2, etc.); } 

    然后,我可以将旧的表单对象(在get()方法中创建)与WebDataBinder从提交的表单值创建的新表单对象进行比较。 如果哈希值不同,则用户更改了某些内容。

    我使用这种方法的问题是,如何保留旧的表单对象? 有没有一种方法可以将其填充到页面的ModelAndView ,该方法可以从GET到POST生存下来? 还是可以通过重载基于db的持久实体,在doPost()方法中重新创建它? 如果Hibernate缓存了我的实体,那么在持久保存任何新更改之前重新创建原始表单对象应该很快。

  2. 与#1类似,但是使用反射而不是对各个字段进行硬编码。 这样,如果添加了任何新的表单字段,我们就不会忘记将它们添加到hashCode()方法中。 这是一个实现:

     public static boolean hasFormChanged(Object form1, Object form2) { return HashCodeBuilder.reflectionHashCode(form1) != HashCodeBuilder.reflectionHashCode(form2); } 

    现在,我知道反射很慢。 在我的测试中,比上面的Objects.hashCode()方法慢大约8-12倍。 但是,我只有大约4个表单字段,在本地计算机上的测试中,基于反射的方法每次调用大约需要3.5 微秒 反射的另一个缺点是,我们需要要留神添加任何新的实例变量到窗体类(或它的父类(ES))的,我们希望在比较中包括。

对于前端解决方案,您可以实现更通用的示例,该示例可以应用于任何页面。 在页面加载时,遍历form元素,然后遍历表单的每个字段并保存其名称和值

例如,

["form1", {field1: "value1"}, {field2 : "value2"}]

在提交之前,您可以检查新表单值是否等于旧表单值,并添加其他属性“已更改”

每个前端解决方案都很难看。 当然最好在服务器端进行

您可以将旧对象存储在httpSession中,也可以第二次请求它(注意,休眠状态默认情况下不使用缓存)。 使用hashCode而不是equals什么意义? 当不相同的对象返回相同的hashCode时,发生碰撞的可能性很小

最直接的方法-再次从Db请求您的对象,并使用equals比较它们

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM