表单的重复提交: 没有完整的进行一次,先请求表单页面->再提交表单过程而完成数据提交

造成的根本原因: 没有完整的进行一次,先请求表单页面->再提交表单过程.

造成重复提交的现象:

  1. 由于服务器缓慢或网络延迟的原因,重复点击提交按钮.
  2. 已经提交成功,刷新成功页面(forward)(请求转发).
  3. 已经提交成功,通过回退,再次点击提交按钮
  • 注意:回退后,刷新表单页面,重新再提交,这时,不是重复提交,而是发送新的请求,在Firefox下,重复提交到同一个地址的操作无效.

案例:

 @WebServlet("/trans")
public class TransferServlet extends HttpServlet{
private static final long serialVersionUID = 1L; protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
String money = req.getParameter("money");
//通过睡眠,模拟网络延迟
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("转出金额:"+money);
out.print("转出金额:"+money);
}
}

在狂点之下,会发现,jsp页面不会有变化,但是通过后台的打印输出可以看到,会不停地输出,说明一直在执行

解决方法:

保证提交保证之前,就必须先请求表单界面,原理和验证码一样.----令牌机制

在第一次请求的时候,请求到表单界面时,创建一个令牌,当点击转账,发送请求的时候,带上这个令牌,发送到下一个界面,在servlet中对这个令牌进行验证,这个令牌在session中一份,在表单中一份,相等说明表单正确,并且把这个session中的令牌销毁掉.

在jsp页面中的代码

      <%
//创建令牌
String token = java.util.UUID.randomUUID().toString();
//存在session中一份,以后做判断
session.setAttribute("TOKEN_IN_SESSION", token);
%> <h3>转账界面</h3>
<form action="/trans" method="post">
<input type="hidden" name="token" value="<%=token%>"/>
转账金额:<input type="text" name="money" min="1" required /><br/>
<input type="submit" value="转账" />
</form>

在TransferServlet中的代码

 @WebServlet("/trans")
public class TransferServlet extends HttpServlet{
private static final long serialVersionUID = 1L; protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
//获取表单中的token值
String token = req.getParameter("token");
//获取session中的token值
String sessionToken = (String) req.getSession().getAttribute("TOKEN_IN_SESSION");
//session中的token容易为空,因为session中的token是需要被销毁的 if (token.equals(sessionToken)) {
//说明令牌相同
req.getSession().removeAttribute("TOKEN_IN_SESSION");
String money = req.getParameter("money");
System.out.println("转出金额:"+money);
out.print("转出金额:"+money);
//最后销毁session中的令牌
}
//如果令牌不同说明就是重复提交,不能提交
}
}

然后呢,为了不想在jsp文件中出现Java代码,把令牌的创建并跳转放在另一个servlet中

 @WebServlet("/transfer")
public class CopyOfTransferServlet extends HttpServlet{
private static final long serialVersionUID = 1L; protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//创建令牌,并跳转到submit.jsp
String token = UUID.randomUUID().toString();
System.out.println(token);
req.getSession().setAttribute("TOKEN_IN_SESSION", token);
req.setAttribute("token", token);
req.getRequestDispatcher("/views/repeatsubmit/submit.jsp").forward(req, resp); }
}

此时jsp文件中就是这个样子

      <h3>转账界面</h3>
<form action="/trans" method="post">
<input type="hidden" name="token" value="${token }"/>
转账金额:<input type="text" name="money" min="1" required /><br/>
<input type="submit" value="转账" />
</form>

比上面的干净了很多,更加整齐,但是还是感觉不好,因为如果在其他地方需要用到,还需要在创建令牌,校验令牌,删除令牌,因此就抽取出来做一个工具类

   TokenUtil.java
1 //令牌的工具类
//创建令牌
//校验令牌
//销毁令牌
public class TokenUtil {
private final static String TOKEN_IN_SESSION = "TOKEN_IN_SESSION";
public static void savaToken(HttpServletRequest req) {
String token = UUID.randomUUID().toString();
System.out.println(token);
req.getSession().setAttribute(TOKEN_IN_SESSION, token);
req.setAttribute("token", token);
} public static boolean validateToken(HttpServletRequest req,
String tokenInrequest) {
//获取session中的token值
String sessionToken = (String) req.getSession().getAttribute(
TOKEN_IN_SESSION);
if (tokenInrequest.equals(sessionToken)) {
req.getSession().removeAttribute(TOKEN_IN_SESSION);
return true;
}
return false;
}
}

这样就好了,使用者只需要调用这个工具类就好了,不需要再去写创建令牌等一系列操作

Java中避免表单重复提交的更多相关文章

  1. java web解决表单重复提交问题

    我们大家再进行web开发的时候,必不可少会遇见表单重复提交问题.今天就来给总结如何解决表单提交问题,欢迎大家交流指正. 首先我们在讨论如何解决表单重复提交问题之前先来解决三个问题:1.什么叫表单重复提 ...

  2. 使用js控制表单重复提交(1加锁,2事件方式,3 EasyUI中解决表单重复提交)

    方法一. var flag = true; $(function() { $("#interested").click(function() { beInterested(); } ...

  3. java web解决表单重复提交

    首先我们在讨论如何解决表单重复提交问题之前先来解决三个问题:1.什么叫表单重复提交?2.什么情况下会出现表单重复提交?3.什么情况需要避免表单重复提交? 什么叫表单提交问题,说白了,就是同一份信息,重 ...

  4. [原创]java WEB学习笔记73:Struts2 学习之路-- strut2中防止表单重复提交

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  5. Java Web之表单重复提交问题

    上篇文章讲了验证码的制作,提及到了一个问题,就是表单重复提交的问题,可能在上次那个验证码中感觉不是那么的重要 现在我新写一个例子,转钱.通过这个例子你就知道表单重复提交有多恐怖了. 先来简单的介绍一下 ...

  6. Struts2中解决表单重复提交

    3. 表单的重复提交问题 1). 什么是表单的重复提交 > 在不刷新表单页面的前提下:  >> 多次点击提交按钮 >> 已经提交成功, 按 "回退" ...

  7. Struts2中防止表单重复提交,global-results定义全局结果处理

    1.在表单中加入<s:token/>标签 2.在动作类中加入token的拦截器 <!--如果单单写 name="token" 会丧失 defaultStack 拦 ...

  8. Struts(二十七):使用token或tokenSession防止表单重复提交

    什么是表单重复提交 表单重复提交包括以下几种情况: 前提:不刷新表单页面 1.多次点击“提交”按钮后,重复提交了多次: 2.已经提交成功之后,按“回退”按钮之后,在点击“提交”按钮后,提交成功: 3. ...

  9. 【Struts2】防止表单重复提交

    一.概述 二.Struts2中解决方案 三.实现步骤 一.概述 regist.jsp----->RegistServlet 表单重复提交 危害: 刷票. 重复注册.带来服务器访问压力(拒绝服务) ...

随机推荐

  1. Read Excel file from C#

    Common way is: var fileName = string.Format("{0}\\fileNameHere", Directory.GetCurrentDirec ...

  2. ldap + kerberos 整合

    第一部分:ldap1. 安装ldap yum install -y openldap openldap-clients openldap-servers openldap-devel 2. 配置lda ...

  3. JDBC操作步骤及数据库连接操作

    http://blog.csdn.net/joywy/article/details/7731305

  4. C语言程序设计第10堂作业

    一.本次课主要内容: 本次课程学习数组,一种最基本的构造类型,它是一组相同类型数据的有序集合.数组中的元素在内存中连续存放,每个元素都属于同一种数据类型,用数组名和下标可以唯一地确定数组元素: (1) ...

  5. linux tar 解压文件时指定文件名

      linux解压文件时指定文件夹名称   wget -O mysql-5.6.15.tar.gz  http://oss.aliyuncs.com/aliyunecs/onekey/mysql/my ...

  6. 在Visual Studio中使用Git命令提示符

    VS2015自带了Git插件,但有时候我觉得Git控制台命令更方便些. VS中本身不能把Git Bush作为浮动窗集成进来,但我们可以通过Power Shell来使用Git命令. ---------- ...

  7. 多线程知识点总结 -NSThread4

    NSThread 三种创建方式 NSThread的对象方法 - (void)threadDemo1 { NSLog(@"before %@", [NSThread currentT ...

  8. JavaScript数据属性与访问器属性

    ES5中对象的属性可以分为‘数据属性’和‘访问器属性’两种. 数据属性一般用于存储数据数值,访问器属性对应的是set/get操作,不能直接存储数据值. 数据属性特性:value.writable.en ...

  9. RadioButtonFor绑定值

    <div class="form-group"> <label class="control-label col-md-2">是否< ...

  10. 通过HttpWebRequest请求与HttpWebResponse响应方式发布接口与访问接口

    一.API接口的编码 1.首页的页面代码: protected void Page_Load(object sender, EventArgs e) { /* * 请求路径:http://xxxx/i ...