客户端防表单重复提交和服务器端session防表单重复提交

33 篇文章 0 订阅

   为了防止用户在客户端重复提交表单,要分析从客户端和服务端对重复提交的表单就行处理,首先是客户端处理重复提交表单,使用JavaScript方法,第一种是只允许表单提交一次,后来的不能再提交,第二种是提交一次后按钮变成不可用,下面是代码的实现

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
/*
 var isCommit = false;
 function doSubmit(){
 	if(! isCommit){
 	isCommit = true;
 		return true;
 	}	else{
 	return false;
 	}
 }*/
 function doSubmit(){//使提交按钮再提交完成后不可用
 	var input = document.getElementById("submit");
 	input.disabled='disabled';
 	return true;
 }
</script>


</head>
<body>
<form action="/Web/servlet/DoFormServlet" method="post" οnsubmit="return doSubmit()">
用户名:<input type="text" name="username"><br>
<input id="submit" type="submit" value="提交" >
</form>
</body>
</html>

但是仅仅在客户端进行处理是远远不够的,这叫只能防的了君子防不了小人,因为可以根据服务器的提交地址自己写一个表单或者去掉JavaScript代码进行自己的提交,这样仍旧无法阻止客户端的表单的重复提交,下面就需要在服务端做手脚,首先需要写一个Servlet用来产生表单,他的想法是产生一个唯一的Id ,通过随机数才产生,然后付到表单上,当表单提交的时候,根据验证这个ID号来判断时候是重复提交表单。


当然,这个随即数的产生不简单,首先使用单例设计模式,减少随机数产生的相似性概率,然后使用当前时间毫秒数加上一个随机数来进行,然后因为这样产生的随机数大小长度不等,所以进行md5编码后再进行BASE64编码,产生长度相等的而且字符都是键盘上可以识别的随机数,放到表单的隐藏域里面去。这个BASE64编码在网络传输中也有很好的作用,表单提交后,处理的Servlet根据放入到Session中的随机数来验证是不是重复提交,如果不是,就进行下面的比如放入到数据库等操作,如果是,则回复请求,说明表单重复提交。下面上代码

首先是产生表单的Servlet

package com.bird.form;

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

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

import sun.misc.BASE64Encoder;

public class FormServlet extends HttpServlet {

	/**
	 * 写给浏览器一个表单,并且防止多次重复提交而创建随机数
	 * @author Bird
	 */
	private static final long serialVersionUID = 1L;

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//产生随机数(表单号 )
		TokenProcessor tp = TokenProcessor.getInstance();
		String token = tp.generateToken();
		
		request.getSession().setAttribute("token", token);
		
		request.getRequestDispatcher("/form.jsp").forward(request, response);
	}

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

	}

}

class TokenProcessor{//令牌发生器 
	/**
	 * 1.把构造方法私有
	 * 2.自己创建一个
	 * 3.对外暴露一个方法,允许获得创建的对象
	 */
	
	private TokenProcessor(){}
	
	private static final TokenProcessor instance = new TokenProcessor();
	
	public static TokenProcessor getInstance(){
		return instance;
	}
	
	public String generateToken(){//获取唯一的表单码
		String token = System.currentTimeMillis() + new Random().nextInt() + "";
		try {
			MessageDigest md5 = MessageDigest.getInstance("md5");
			byte[] md = md5.digest(token.getBytes());
			
			//base64进行编码
			BASE64Encoder encoder = new BASE64Encoder();
			return encoder.encode(md);
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
	}
}

然后是那个JSP页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="/Web/servlet/DoFormServlet" method="post">
	<input type="hidden" name="token" value="${token}">
	用户名:<input type="text" name="username"><br/>
	<input type="submit" value="提交">
	</form>
</body>
</html>

然后是处理提交请求的Servlt

package com.bird.form;

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 {

	/**
	 * 处理表单的重复提交
	 * @author Bird
	 */
	private static final long serialVersionUID = 1L;

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		boolean b = isTokenValue(request);
		if(!b){
			System.out.println("请不要重复提交");
			return;
		}
		request.getSession(false).removeAttribute("token");
		System.out.println("向数据库中注入数据");
	}

	private boolean isTokenValue(HttpServletRequest request) {
		String clinet_token = request.getParameter("token");
		if(clinet_token == null){
			
			return false;
		}
		String server_token = (String) request.getSession(false).getAttribute("token");
		if(server_token == null){
			
			return false;
		}
		if(!server_token.equals(clinet_token)){
			
			return false;
		}
		
		return true;
	}

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

	}

}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值