1. 程式人生 > >客戶端防表單重複提交和伺服器端session防表單重複提交

客戶端防表單重複提交和伺服器端session防表單重複提交

   為了防止使用者在客戶端重複提交表單,要分析從客戶端和服務端對重複提交的表單就行處理,首先是客戶端處理重複提交表單,使用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" onsubmit="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);

	}

}