`

36、servlet--防止表单重复提交

    博客分类:
  • mvc
 
阅读更多
1、在网络延迟会或服务器反应过慢的情况下让用户有时间点击多次submit按钮导致表单重复提交
2、用户提交后,点击刷新
3、用户提交后,点击后退,继续提交

解决方法:
1、js防刷新
2、session防刷新


js防止刷新只能针对网络延迟:
  <script type="text/javascript">
    function dosubmit(){
      //获取表单提交按钮
     var btnSubmit = document.getElementById("submit");
    //将表单提交按钮设置为不可用,这样就可以避免用户再次点击提交按钮
     btnSubmit.disabled= "disabled";
     //返回true让表单可以正常提交
     return true;
    }
       </script>
  </head>
  
  <body>
       <legend>用户注册</legend>
  <form id="myform" action="<%=path %>/servlet/FormServlet" onsubmit="return dosubmit()" method="post">
   <label >用户名</label>
    <input name="name" type="text" /><br>
  <label >密码</label>
  <input  name="password" type="text"  />
 <input class="submit" type="submit" id="submit" value="Submit"/>
</form>
  </body>

或者:
   var isCommitted = false;//表单是否已经提交标识,默认为false
          function dosubmit(){
              if(isCommitted==false){
                isCommitted = true;//提交表单后,将表单是否已经提交标识设置为true
                 return true;//返回true让表单正常提交
             }else{
                 return false;//返回false那么表单将不提交
             }
         }}


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

  具体的做法:


被拒绝的情况:
1、当前用户的Session中不存在token;
2、用户提交的表单数据中token="";
3、request与session中的token不一致;

<input type="hidden" name="token" value="${token}"/>
生成token跳转到登陆页面:
public class FromToken extends HttpServlet {


	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		 String token = TokenUtil.getInstance().createToken();//创建令牌
		 request.getSession().setAttribute("token", token);  //在服务器使用session保存token(令牌)
		 request.getRequestDispatcher("/session/login.jsp").forward(request, response);//跳转到form.jsp页面
		 return;
	}

	
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		 doGet(request,response);

	}

}


token生成器:
package org.nick.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

import sun.misc.BASE64Encoder;


public class TokenUtil {
	     /*
	      *单例设计模式(保证类的对象在内存中只有一个)
	      *1、把类的构造函数私有
	      *2、自己创建一个类的对象
	      *3、对外提供一个公共的方法,返回类的对象
	      */
	     private TokenUtil(){}
	     
	     private static final TokenUtil instance = new TokenUtil();
	     
	     /**
	      * 返回类的对象
	      * @return
	     */
	     public static TokenUtil getInstance(){
	         return instance;
	     }
	     
	     /**
	      * 生成Token
	      * Token:Nv6RRuGEVvmGjB+jimI/gw==
	      * @return
	      */
	     public String createToken(){  //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);
	         }
	     }
	 }


提交验证:
package org.nick.server;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.nick.util.TokenUtil;

public class FormServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		     boolean b = isRepeatSubmit(request);//判断用户是否是重复提交
		     if(b==true)
		     {
		    	 System.out.println("重复提交");
		    	 //不要跳回注册
		    	 request.getRequestDispatcher("/session/login.jsp").forward(request, response);
		    	 return;
		     }
             
			 String  name = request.getParameter("name");
			 //if(操作成功){
			 System.out.println("数据库反应:inset one  data :"+name+"操作成功!");
			 request.getSession().removeAttribute("token");//移除session中的token
			 //不要跳回注册
			 request.getRequestDispatcher("/session/login.jsp").forward(request, response);
			 return;

	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		 doGet(request,response);
	}
	
	 /**
     * 判断客户端提交上来的令牌和服务器端生成的令牌是否一致
     * @param request
     * @return 
     *         true 用户重复提交了表单 
     *         false 用户没有重复提交表单
     */
    private boolean isRepeatSubmit(HttpServletRequest request) {
        String client_token = request.getParameter("token");
        System.out.println(client_token+"client");
        //、如果用户提交的表单数据中没有token,则用户是重复提交了表单
       if(client_token==null || client_token.equals("")){
            return true;
        }
        //取出存储在Session中的token
        String server_token = (String) request.getSession().getAttribute("token");
        System.out.println(server_token+"session");
        //、如果当前用户的Session中不存在Token(令牌),则用户是重复提交了表单
        if(server_token==null){
            return true;
        }
        //、存储在Session中的Token(令牌)与表单提交的Token(令牌)不同,则用户是重复提交了表单
        if(!client_token.equals(server_token)){
            return true;
        }
        
        return false;
    }

}


不能满足的:
1、点击后退再刷新 再提交
2、其他跳转到FromToken的请求

因为这两种都会重新生成token放在session中,同时也提供了重新注册的机制;

服务端删除session中的token的时机很重要,防止每个session都有token属性。
  • 大小: 11 KB
分享到:
评论

相关推荐

    Jsp+Servlet+Cookie实现记住密码,自动登录,防止表单提交,记录登录次数

    Jsp+Servlet+Cookie实现记住密码,自动登录,防止表单提交,记录登录次数的新手例子。简单明了,大量注释,El表达式等。

    JSP使用自定义标签防止表单重复提交的方法

    本文实例讲述了JSP使用自定义标签防止表单重复提交的方法。分享给大家供大家参考。具体如下: 1. 编写servelt: package cn.itcast.apsliyuan.web.servlet; import java.io.IOException; import javax.servlet....

    健身俱乐部Web网站-JSP+Servlet+Hibernate+jQuery+Ajax

    7.由于是第一次做网站,且时间比较紧(这段时间期末考试),所以对于一些细节问题,如防止表单重复提交、某些页面的访问权限控制(基本的访问权限控制已经实现,但是有些比如像俱乐部服务员可以不登陆直接通过URL...

    JSP实用技巧集合,jsp编程的一些小技巧总结

    103.使用session对象防止表单重复提交? 104.获取用户真实IP地址? 105.获取请求中的所有参数? 106.获取完整的请求URL? 107.在重新显示表单时保留用户已经输入的合法数据? 108.使用选代器遍历集合 109.使用特定字符串...

    struts2课程笔记

    struts2知识点:处理流程,基本配置,与servlet的API解耦,结果类型,通配符和动态方法的调用,类型转换,文件上传,拦截器,表单验证,国际化,OGNL表达式,UI标签,模型驱动,防止表单重复提交,项目练习知识点:...

    jsp编程技巧集锦

    使用session对象防止表单重复提交? 104.获取用户真实IP地址? 105.获取请求中的所有参数? 106.获取完整的请求URL? 107.在重新显示表单时保留用户已经输入的合法数据? 108.使用选代器遍历集合 109....

    百度地图开发java源码-TypicalWebProject:一个典型的JavaWeb项目

    令牌机制防止表单重复提交。 注册表单的JS验证、Ajax用户名唯一性验证等等。 开发环境: jdk1.8+Tomcat 9+Mysql 5.7+Eclipse(本人用Oracle也做了一版,上传的程序是用的Mysql版) 项目功能模块: 用户注册、登录、...

    Struts2入门教程(全新完整版)

    5. TokenInterceptor防止表单重复提交。 34 6.使用拦截器实现权限验证 35 7.拦截器中的注解 37 8.使用PreResultListener实现回调 39 六、使用标签 40 1.基础表单标签 40 2.单选按钮和复选框: 41 3.三种方式实现下拉...

    达内java培训目录

    Struts2 Struts2核心控制流程、Ognl、Action、Interceptor、Result、FreeMarker、Struts2标记库、Struts2扩展、Struts2应用技巧(输入验证、消息国际化、文件上传和下载、防止重复提交等)。 熟练掌握Struts2核心...

    structs程序设计从入门到精通word文档

    9.3 Struts令牌机制,防止重复提交 13 9.4 StrutsAction单态陷阱,请谨慎使用全局变量 13 9.5 Struts异常处理 13 第10章 struts中使用国际化(i18n) 13 10.1 struts国际化程序尝试 13 10.1 Java对i18n的支持 14 10.1...

    深入浅出Struts 2 .pdf(原书扫描版) part 1

    第15章 防止重复提交 252 15.1 标记管理 252 15.2 使用Token拦截器 253 15.3 使用Token Session拦截器 256 15.4 小结 257 第16章 调试与性能分析 258 16.1 debug标签 258 16.2 Debugging拦截器 259 16.3 性能分析 ...

    深入浅出Struts2(附源码)

    第15章防止重复提交 252 15.1 标记管理 252 15.2 使用Token拦截器 253 15.3 使用Token Session拦截器 256 15.4 小结 257 第16章调试与性能分析 258 16.1 debug标签 258 16.2 Debugging拦截器 259 16.3 性能...

    JavaScript完全自学宝典 源代码

    7.6.html 防止onresize事件重复执行。 7.7.html onerror事件相关处理。 7.8.html onsubmit事件使用方法。 7.9.html 失去焦点时检验文本框的值。 7.10.html 获得焦点时文本框样式更改。 img.JPG...

Global site tag (gtag.js) - Google Analytics