表单重复提交主要有以下三种情况:

1. 在网络延迟的情况下让用户有时间点击多次submit按钮导致表单重复提交

2. 表单提交后用户点击【刷新】按钮导致表单重复提交

3. 用户提交表单后,点击浏览器的【后退】按钮回退到表单页面后进行再次提交

解决办法主要有以下几种:

1. 利用JavaScript防止表单重复提交

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
<title>Form表单</title>
<script type="text/javascript">
var isCommitted = false;//表单是否已经提交标识,默认为false
function dosubmit(){
if(isCommitted==false){
isCommitted = true;//提交表单后,将表单是否已经提交标识设置为true
return true;//返回true让表单正常提交
}else{
return false;//返回false那么表单将不提交
}
}
</script>
</head> <body>
<form action="${pageContext.request.contextPath}/servlet/DoFormServlet" onsubmit="return dosubmit()" method="post">
用户名:<input type="text" name="username">
<input type="submit" value="提交" id="submit">
</form>
</body>
</html>

另一种方式就是表单提交之后,将提交按钮设置为不可用,让用户没有机会点击第二次提交按钮

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

  使用JavaScript防止表单重复提交的做法只对上述提交到导致表单重复提交的三种场景中的【场景一】有效,而对于【场景二】和【场景三】是没有用,依然无法解决表单重复提交问题。对于【场景二】和【场景三】导致表单重复提交的问题,既然客户端无法解决,那么就在服务器端解决,在服务器端解决就需要用到session了。

  具体的做法:在服务器端生成一个唯一的随机标识号,专业术语称为Token(令牌),同时在当前用户的Session域中保存这个Token,然后将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端,然后在服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。
  在下列情况下,服务器程序将拒绝处理用户提交的表单请求:

    1. 存储Session域中的Token(令牌)与表单提交的Token(令牌)不同。

    2. 当前用户的Session中不存在Token(令牌)。

    3. 用户提交的表单数据中没有Token(令牌)。

步骤一:创建FormServlet,用于生成Token(令牌)和跳转到form.jsp页面

 package xdp.gacl.session;

 import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; public class FormServlet extends HttpServlet {
private static final long serialVersionUID = -884689940866074733L; public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { 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页面
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
} }

步骤二:在form.jsp中使用隐藏域来存储Token(令牌)

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>form表单</title>
</head> <body>
<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>
</body>
</html>

步骤三:DoFormServlet处理表单提交

 package xdp.gacl.session;

 import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; public class DoFormServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { boolean b = isRepeatSubmit(request);//判断用户是否是重复提交
if(b==true){
System.out.println("请不要重复提交");
return;
}
request.getSession().removeAttribute("token");//移除session中的token
System.out.println("处理用户提交请求!!");
} /**
* 判断客户端提交上来的令牌和服务器端生成的令牌是否一致
* @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中的token
String 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;
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
} }

生成Token的工具类TokenProccessor

 package xdp.gacl.session;

 import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import sun.misc.BASE64Encoder; 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(){ //checkException
// 7346734837483 834u938493493849384 43434384
String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
//数据指纹 128位长 16个字节 md5
try {
MessageDigest md = MessageDigest.getInstance("md5");
byte md5[] = md.digest(token.getBytes());
//base64编码--任意二进制编码明文字符 adfsdfsdfsf
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(md5);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}

一般场景下,利用这种方法处理表单重复提交

JavaWeb温习之防止表单重复提交的更多相关文章

  1. JavaWeb使用Session防止表单重复提交

    在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交. 1.什么是表单 ...

  2. (转)JavaWeb学习总结(十三)——使用Session防止表单重复提交

    如何防止表单重复提交 在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复 ...

  3. JavaWeb 如何防止表单重复提交 - 使用Token,令牌

    JavaWeb 如何防止表单重复提交 - 使用Token,令牌 说到重复提交 ,应该想到两种场景:1. 在下单,或者支付 这种情况 那么不允许  刷新,不允许后退再点击提交(后退之后提交会失败,修改了 ...

  4. JavaWeb防止表单重复提交(转载)

    转载自:http://blog.csdn.net/ye1992/article/details/42873219 在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用 ...

  5. JavaWeb学习总结(十三)——使用Session防止表单重复提交

    在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交. 一.表单重复提 ...

  6. javaWeb学习总结(7)- 使用Session防止表单重复提交

    在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交. 一.表单重复提 ...

  7. JavaWeb学习 (十二)————使用Session防止表单重复提交

    在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交. 一.表单重复提 ...

  8. javaweb防止表单重复提交

    参考孤傲苍狼 https://www.cnblogs.com/xdp-gacl/p/3859416.html 场景一:在网络延迟的情况下让用户有时间点击多次submit按钮导致表单重复提交 场景二:表 ...

  9. JavaWeb学习总结(十一):Session解决form表单重复提交

    在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交. 一.表单重复提 ...

随机推荐

  1. golang web开发获取get、post、cookie参数

    在成熟的语言java.python.php要获取这些参数应该来讲都非常简单,过较新的语言golang用获取这些个参数还是费了不少劲,特此记录一下. golang版本:1.3.1在贴代码之前如果能先理解 ...

  2. javascript商务通

    //左侧就医服务新 document.write("<style type='text/css'>"); document.write(".left_swt{ ...

  3. javascript 商务通

    /*下面的才是新的商务通*/ var swt_autoDisplay_times=15;/*商务通自动弹出时间,秒为单位*/ var float_left_ad_display_Init=0;/*在允 ...

  4. iOS边练边学--plist文件,懒加载,模型初使用--补充instancetype

    一.什么是plist文件 1>将数据直接写在代码里面,不是一种合理的做法.如果数据经常修改,就要经常翻开对应的代码进行修改,造成代码扩展性低 2>因此,可以考虑将经常变得数据放在文件中进行 ...

  5. selenium测试(Java)--下载文件(十六)

    下载文件需要在Firefox 的profile属性中配置一些参数,如下面的代码: package com.test.download; import java.io.File; import org. ...

  6. Android ArryaList 笔记

    Arraylist相当于动态数组,可以动态的添加或者删除其中的元素. 参考链接 http://beginnersbook.com/2013/12/java-arraylist/ package com ...

  7. javax.naming.NoInitialContextException错误的解决方案

    今天,学习用了一下nutz框架,写了一个HelloWorld的小程序,在用jndi配置数据源时,写了一个测试类,并在main方法中调用了jndi获得数据库连接,但是报错了,错误信息如下: javax. ...

  8. 学习 C++,关键是要理解概念,而不应过于深究语言的技术细节

    学习 C++学习 C++,关键是要理解概念,而不应过于深究语言的技术细节. 学习程序设计语言的目的是为了成为一个更好的程序员,也就是说,是为了能更有效率地设计和实现新系统,以及维护旧系统. C++ 支 ...

  9. (记录)eclipse常用设置步骤

    代码风格文件导入: https://blog.csdn.net/wangming520liwei/article/details/53911736 注释中的author修改: https://jing ...

  10. 手淘H5移动端适配方案flexible源码分析

    移动端适配一直是一个值得探讨的问题,在业余时间我找了一些页面,查看了一些厂商对于移动端H5页面的适配方案,看到了几个典型的例子,今天就来记录一下我看到的第一个典型的例子,也是我们公司目前普通H5项目正 ...