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

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

造成重复提交的现象:

  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. 中小网站如何使用谷歌Adsence国际化优势赚钱?

    劲捷电子信息有限公司是一家拿了美国风险投资的互联网公司.他的创办人祁劲松2005年加入AdSense,迄今收获颇丰,为此他还写了一本 <Google AdSense实战宝典>.在祁劲松看来 ...

  2. EasyUI使用JSON保存数据

    目前来说,使用JSON保存数据比较方便,前台可以不用Test.aspx 页面,可以直接用Html页面,使用.aspx页面的弊端就不在这里熬述. 具体步骤如下: 1.新建一个Html页面,命名为Test ...

  3. Directory 与 DirectoryInfo 的区别

    Directory 与 DirectoryInfo 这两个能够实现大多数相同的功能.区别可分为两点:一.静态与实例调用前者必须被实例化后才能使用,而后者则只提供了静态的方法.如果多次使用某个对象一般使 ...

  4. 一步一步搭框架(asp.netmvc+easyui+sqlserver)-03

    一步一步搭框架(asp.netmvc+easyui+sqlserver)-03 我们期望简洁的后台代码,如下: using System; using System.Collections.Gener ...

  5. Spring3.0 与 MyBatis框架 整合小实例

    本文将在Eclipse开发环境下,采用Spring MVC + Spring + MyBatis + Maven + Log4J 框架搭建一个Java web 项目. 1. 环境准备: 1.1 创建数 ...

  6. Spring中Bean的生命周期方法

    Bean的生命周期方法 src\dayday\Car.java package dayday;import com.sun.org.apache.xpath.internal.SourceTree;i ...

  7. unix basic command

    1. get start Command Example Description ls ls ls -a ls -l 输出目录文件 输出文件包括隐藏文件 输出文件详细信息 pwd pwd show p ...

  8. MySQL数据库4 - 查看数据表

    一. 查看表的基本结构 语法:DESCRIBE/DESC TABLE_NAME 查询结果含义: Field: 字段名 Type: 字段类型 Null: 是否可以为空 Key: 是否编制索引 defau ...

  9. 没有为扩展名.htm注册的生成提供程序,没有为扩展名.html注册的生成提供程序

    在web.config中添加下面这段 代码如下 <buildProviders> <add extension=".html" type="System ...

  10. javascript运动应用

    多物体运动框架: 1.多个盒子同时运动:move(obj,target)多一个参数 <!DOCTYPE html><html><head> <title> ...