1. 为什么会出现表单重复提交问题?

  1. 网络延迟的情况下用户多次点击submit按钮导致表单重复提交
  2. 用户提交表单后,点击【刷新】按钮导致表单重复提交(点击浏览器的刷新按钮,就是把浏览器上次做的事情再做一次,因为这样也会导致表单重复提交
  3. 用户提交表单后,点击浏览器的【后退】按钮回退到表单页面后进行再次提交

2.解决方案

2.1 前端解决方案(治标不治本)

2.1.1用JavaScript控制Form表单只能提交一次

主要代码:

<form action="${pageContext.request.contextPath}/servlet/DoFormServlet" οnsubmit="return dosubmit()" method="post">用户名:<input type="text" name="username"><input type="submit" value="提交" id="submit">
</form><head><title>Form表单</title><script type="text/javascript">var isCommitted = false;//表单是否已经提交标识,默认为falsefunction dosubmit(){if(isCommitted==false){isCommitted = true;//提交表单后,将表单是否已经提交标识设置为truereturn true;//返回true让表单正常提交} else {return false;//返回false那么表单将不提交}}</script>
</head>

2.1.2提交以后将提交按钮设置为不可用(体验可能不太好)

主要代码:

function dosubmit(){//获取表单提交按钮var btnSubmit = document.getElementById("submit");//将表单提交按钮设置为不可用,这样就可以避免用户再次点击提交按钮btnSubmit.disabled= "disabled";//返回true让表单可以正常提交return true;
}

2.1.3提交以后将页面关闭(可能用户体验不好)

2.1.4提交以后将页面数据刷新 这个时候将本条记录的主键id拿到,后端进行插入的时候看看主键id是否存在决定进行插入或者修改

2.2 后端解决方案

2.2.1利用Session防止表单重复提交

主要步骤:

  1. 在服务器端生成一个唯一的随机标识号,专业术语称为Token(令牌),并在当前用户的Session域中保存这个Token

token生成类

public class TokenProccessor {/**单例设计模式(保证类的对象在内存中只有一个)*1、把类的构造函数私有*2、自己创建一个类的对象*3、对外提供一个公共的方法,返回类的对象*/private TokenProccessor(){}private static final TokenProccessor instance = new TokenProccessor();/*** 返回类的对象* @return*/public static TokenProccessor getInstance(){return instance;}/*** 生成Token* Token:Nv6RRuGEVvmGjB+jimI/gw==* @return*/public String makeToken(){String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";//数据指纹   128位长   16个字节  md5try {MessageDigest md = MessageDigest.getInstance("md5");byte md5[] =  md.digest(token.getBytes());//base64编码--任意二进制编码明文字符   adfsdfsdfsfBASE64Encoder encoder = new BASE64Encoder();return encoder.encode(md5);} catch (NoSuchAlgorithmException e) {throw new RuntimeException(e);}}
}
String token = TokenProccessor.getInstance().makeToken();//创建令牌
System.out.println("在FormServlet中生成的token:"+token);
request.getSession().setAttribute("token", token);  //在服务器使用session保存token(令牌)
request.getRequestDispatcher("/form.jsp").forward(request, response);//跳转到form.jsp页面
  1. 将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端
<form action="${pageContext.request.contextPath}/servlet/DoFormServlet" method="post"><%--使用隐藏域存储生成的token--%><%--<input type="hidden" name="token" value="<%=session.getAttribute("token") %>">--%><%--使用EL表达式取出存储在session中的token--%><input type="hidden" name="token" value="${token}"/> 用户名:<input type="text" name="username"> <input type="submit" value="提交">
</form>
  1. 在服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。
/*** 判断客户端提交上来的令牌和服务器端生成的令牌是否一致* @param request* @return *         true 用户重复提交了表单 *         false 用户没有重复提交表单*/
private boolean isRepeatSubmit(HttpServletRequest request) {String client_token = request.getParameter("token");//1、如果用户提交的表单数据中没有token,则用户是重复提交了表单if(client_token==null){return true;}//取出存储在Session中的tokenString server_token = (String) request.getSession().getAttribute("token");//2、如果当前用户的Session中不存在Token(令牌),则用户是重复提交了表单if(server_token==null){return true;}//3、存储在Session中的Token(令牌)与表单提交的Token(令牌)不同,则用户是重复提交了表单if(!client_token.equals(server_token)){return true;}return false;
}

doGet方法中:


boolean b = isRepeatSubmit(request);//判断用户是否是重复提交
if(b==true){System.out.println("请不要重复提交");return;
}
request.getSession().removeAttribute("token");//移除session中的token
System.out.println("处理用户提交请求!!");

对于【场景二】和【场景三】导致表单重复提交的问题,既然客户端无法解决,那么就在服务器端解决,在服务器端解决就需要用到session了。使用token的方法能解决【场景二】和【场景三】的情况。

2.3 前端加后端的解决方案

思路: 前端提交以后,页面弄一个加载动画,后端处理完成以后将本条数据的主键id返回前端,前端第二次请求的时候把主键id附上值即可。

总结:

常见的方法有四种:

  • 方法一:禁用掉“提交(注册)”按钮,当用户第一次点击提交注册按钮时,事务已经提交了,但是网络存在不稳定性,可能没有及时作出响应,这时用户可能会认为没有点击提交按钮,进而会再次点击提交按钮,
    这是不符合我们的业务逻辑的,因此,我们可以在用户第一次点击提交按钮之后,立刻将提交按钮设置为不可用状态(例如:变灰),用户就不会再次提交了。

  • 方法二:采用页面重定向,在用户点击提交按钮之后,转向一个新的页面,提示用户提交成功。

  • 方法三:采用标志,在一个会话中,当用户请求一个表单时,服务器端在发送页面的时候可以生成一串密文(也可以是随机数),跟随页面同时发给客户端,当客户端填写好表单后,点击提交按钮,再次将这个密文发回到服务器端,并和服务器端的密文进行比对,如果相同,则开始处理业务,如果不相同,则不处理此次业务(像互联网金融行业大多采用这种方式)。

  • 方法四:利用服务器端的数据库,可以在数据库的表里添加相关的约束来防止重复提交,但是这样会增加数据库的负载。

上面的四种方法各有利弊,我们可以根据项目的实际情况来选择,也可以将这些方法组合起来使用。

参考链接;https://www.jianshu.com/p/5fd07359ad22
https://www.cnblogs.com/guozhenqiang/p/5439455.html

解决重复提交问题(前端和后端的解决方案java版)相关推荐

  1. java后端解决重复提交问题

    一.为什么会出现重复提交? 主要是由于网络的延迟问题以及页面刷新的操作. 二.表单的重复提交会导致的问题? 主要能够造成很多脏数据. 三.解决的办法: 3.1 前端解决办法:通过前端的方法将提交按钮变 ...

  2. Spring AOP + Redis解决重复提交的问题

    Spring AOP + Redis解决重复提交的问题 用户在点击操作的时候,可能会连续点击多次,虽然前端可以通过设置按钮的disable的属性来控制按钮不可连续点击,但是如果别人拿到请求进行模拟,依 ...

  3. 一招教你使用注解处理幂等问题 8种方案解决重复提交

    一招教你使用注解处理幂等问题 8种方案解决重复提交 参考文章: (1)一招教你使用注解处理幂等问题 8种方案解决重复提交 (2)https://www.cnblogs.com/xxmyz/p/1116 ...

  4. 前后端分离重复提交_java+react前后端分离项目处理重复提交问题

    重复提交的问题在web开发中是很常碰到的一个问题,主要分为前端和后端两种途径解决,前端处理一般采用提交事件后,禁止用户再次点击提交按钮,等待服务端结果再重置提交按钮状态. 本文着重介绍,通过java后 ...

  5. 表单重复提交(前端未做单击防重复点击策略)

    表单重复提交导致重复添加,用token解决:提交前的请求会给前端一token,后端将这token存在缓存中,表单提交时要带上这token,后端校验token通过执行业务逻辑,后端 并删除缓存中的tok ...

  6. 8种方案解决重复提交问题

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:锦成同学 链接:juejin.im/post/5d31928 ...

  7. 8种方案解决重复提交问题!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 本文来源:juejin.im/post/5d31928c51882 ...

  8. 8 种方案解决重复提交问题!你选择哪一种呀?

    1.什么是幂等 在我们编程中常见幂等 select查询天然幂等 delete删除也是幂等,删除同一个多次效果一样 update直接更新某个值的,幂等 update更新累加操作的,非幂等 insert非 ...

  9. spring项目使用redis分布式锁解决重复提交问题

    场景演示 假设有一个录入学生信息的功能,为了便于演示,要求不能有重名的学生,并且数据库对应字段没有做唯一限制. @GetMapping("/student/{name}")publ ...

最新文章

  1. Jquery源码分析之匿名函数的自执行
  2. 1418 This function has none of DETERMINISTIC,NO SQL,or R
  3. 官方版下载_药店大学app官方版下载
  4. Java加视频特效,实现伪原创
  5. Appcan——Box
  6. 论文笔记(Neural Graph Collaborative Filtering)
  7. Python之Django之views中视图代码重复查询的优化
  8. 从传统企业谈大数据的战略意义
  9. maven 打包java项目_如何使用maven打包java项目?
  10. 独自研发3年,双平台上线,我是如何从零开始做这款独立游戏的?
  11. Tableau的维度、度量和连续、离散的区分
  12. 流程管理体系实施策略
  13. 义隆单片机CALL 与JMP的区别
  14. 今日头条面试题,供大家参考
  15. 黑镜成真!3分钟看懂马斯克直播脑机接口,芯片植入猪脑,活猪演示
  16. DZZOffice(大桌子)企业文档协同平台教程系列(二)——应用安装、系统设置和使用
  17. 【pandas】df.str.contains包含多个值写法
  18. 产品管理——何为用户体验?附《用户体验的要素》PDF版下载
  19. 2021-12-08:扑克牌中的红桃J和梅花Q找不到了,为了利用剩下的牌做游戏,小明设计了新的游戏规则: 1) A,2,3,4....10,J,Q,K分别对应1到13这些数字,大小王对应0; 2) 游
  20. ImmutableList hessian2序列化失败问题分析

热门文章

  1. python 3.10.1 安装教程
  2. LocalCache本地缓存分享
  3. matlab例题(阶乘,解方程,数字加密输出)
  4. 基于PaddleDetection-YOLOV3做一个完整的图形目标检测项目
  5. Linux - dsta 命令详解
  6. js jquery学习资料
  7. 超级搜索术前4节课思维导图
  8. 当清晨的第一缕阳光洒在我的头发上, 我知道,一个崭新的太阳升起来了
  9. 通达信软件接口如何更新股票价格指数?
  10. 计算机组成原理——中央处理器-数据通路(课程笔记)