Java后端如何过滤重复提交问题

引言

在Web开发中,重复提交是一个常见的问题。当用户在网页上进行表单提交操作时,由于网络延迟或者用户的操作不当,可能导致同一请求被多次提交。这样会给服务器带来不必要的压力,也会对系统产生一些意想不到的结果。在Java后端开发中,我们可以通过一些技术手段来解决这个问题。

问题分析

在分析重复提交问题之前,我们首先需要明确一下重复提交的原因。常见的几种情况包括:

  1. 网络延迟:由于网络不稳定或者服务器响应较慢,用户在提交表单之后可能长时间没有收到响应,于是会不自觉地再次点击提交按钮。
  2. 用户误操作:用户可能会不小心多次点击提交按钮,或者在提交之后立即刷新页面导致再次提交。
  3. 页面跳转:用户在提交表单之后,可能会通过返回、刷新或者重新输入URL等操作回到原来的页面,再次进行表单提交。

根据以上分析,我们可以得出一些解决重复提交问题的思路。

解决思路

前端措施

  1. 禁用提交按钮:在表单提交之后,将提交按钮禁用,避免用户重复点击。
  2. 显示加载状态:在表单提交之后,显示一个加载中的状态,避免用户多次点击。
  3. 重定向页面:在表单提交之后,将页面重定向到一个新的页面,避免用户通过返回、刷新等操作重复提交。

后端措施

  1. 生成唯一标识:在用户首次提交表单时,后端生成一个唯一标识,并将其返回给前端。在后续的提交中,前端需要将该标识一同提交给后端。
  2. 标识有效性验证:后端在接收到表单提交请求后,首先验证该唯一标识的有效性。如果该标识已经被使用过,则可以判断为重复提交,直接返回错误响应。
  3. 标识存储过滤:后端可以将已经使用过的唯一标识存储到缓存或者数据库中,在后续请求中进行过滤。当检测到重复提交时,直接返回错误响应。

代码示例

下面我们通过一个示例来演示如何在Java后端中实现重复提交过滤。

前端代码

<form action="/submit" method="post" onsubmit="return submitForm(this)">
  <input type="text" name="name" required>
  <input type="submit" value="Submit">
</form>

<script>
  function submitForm(form) {
    // 禁用提交按钮
    form.querySelector('[type="submit"]').disabled = true;
    // 显示加载状态
    form.classList.add('loading');
    // 重定向页面
    form.setAttribute('action', '/submit?redirect=true');
    return true;
  }
</script>

后端代码

@RestController
public class SubmitController {

  // 存储已使用的标识,可以使用缓存或者数据库来实现
  private Set<String> usedTokens = new HashSet<>();

  @PostMapping("/submit")
  public String submitForm(@RequestParam("name") String name, @RequestParam(value = "token", required = false) String token) {
    // 验证标识有效性
    if (StringUtils.isEmpty(token) || usedTokens.contains(token)) {
      return "Error: Duplicate submission";
    }
    
    // 处理表单提交
    // ...

    // 添加已使用的标识
    usedTokens.add(token);

    return "Success";
  }
}

甘特图

下面是一个使用甘特图来展示解决重复提交问题的时间分布情况。

gantt
  title 解决重复提交问题甘特图

  section 前端
    表单提交: done, 2022-05-01, 1d
    禁用提交按钮: done, 2022-05-01, 1d
    显示加载状态: done,