表单重复提交问题
1.表单重复提交的根本原因
- 没有完整的进行 一次请求页面 —> 提交页面的过程 而完成数据提交
2.造成重复提交的现象
- 由于服务器缓慢或者网速原因,重复点击按钮
- 已经提交成功,刷新成功页面
- 提交成功后,通过回退,再次点击提交按钮
3.解决方案
从根本原因入手:没有进行完整的两次请求
第一次:先请求表单页面
第二次:再提交表单请求
解决方案:必须执行第二次之前,必须执行第一次。
这里的原理 和 验证码的原理是类似的
通过口令(token)验证 :请求产生一个随机数 和 Session中的随机数 比较
若相同 进入后面代码逻辑 消除本次Session的随机数(口令使用一次)
进入表单页面时要 请求的Servlet中的service方法
该方法生成一个随机数 放入Session中
再放入Request中 用于跳转表单页面时 随机数的传递
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String token = UUID.randomUUID().toString();
// 将token放进 Session中 后面进行验证
req.getSession().setAttribute("TOKEN_IN_SESSION", token);
// 将token值放进Request请求中 用于给jsp页面的隐藏域token设值
req.setAttribute("token", token);
// 跳到jsp页面
req.getRequestDispatcher("/repeatsubmit/transfrom.jsp").forward(req, resp);
}
表单页面(transfrom.jsp):
这里有一个隐藏input元素 用来存放上面Servlet传过来的随机数
<body>
<form action="/repeatsubmit" method="POST">
转账:<input type="text" name = "money" required="required"><br>
<input type="hidden" name = "token" value=${token}><br>
<input type="submit" value="我要转账">
</form>
</body>
当表单点击提交按钮后 会交给一个/repeatsubmit的Servlet去处理
该Servlet的service方法: 将表单中的隐藏的随机数和Session的随机进行比较
若一样 则表示成功提交 并销毁Session中的随机数
如果现在刷新页面等重复提交操作,表单的随机数还是原来的 而Session中的随机数是null
一比较,就会进入重复提交的代码逻辑处理操作
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String tokenInRequest = req.getParameter("token");
String tokenInSession = (String) req.getSession().getAttribute("TOKEN_IN_SESSION");
if (tokenInRequest.equals(tokenInSession)) {
// 相等 则销毁Session 口令只使用一次
req.getSession().removeAttribute("TOKEN_IN_SESSION");
String money = req.getParameter("money");
System.out.println("转出:" + money);
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("转账成功!");
}else {
System.out.println("已重复提交!");
}
}