一:使用JavaScript來防止表單重複提交javascript
有三種場景:1:在網絡延遲的狀況下讓用戶有時間點擊屢次submit致使重複提交html
2:表單提交後點擊「刷新」按鈕致使重複提交java
3:提交後,點擊瀏覽器的後退而後再次提交設計模式
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<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;
}網絡
js只能解決問題1,可是2,3解決不了。session
利用session解決2和3:在服務器端解決dom
作法:在服務器端生成一個惟一的隨機標識號,專業術語:Token(令牌)。同時在當前用戶的Session中保存這個Token。而後將Token發送到客戶端的Form表單中jsp
在表單中使用隱藏域來存儲這個Token。表單提交的時候連同這個Token一塊兒提交到服務器端。而後在服務器端判斷客戶端提交上來的Token與服務器生成的是否同樣。不同就是重複提交了,此時服務器就不能夠處理重複提交的表單。處理完後清除當前用戶的Session中存儲的標識號。
在下列狀況中,服務器程序將拒絕處理
1:存儲session中的Token與表單提交的Token不一樣。
2:當前用戶的session中不存在token
3:用戶提交的表單數據中沒有Token
form.jsp頁面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>Form表單</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/demo02" method="post">
<%--使用EL表達式取出存儲在session中的token--%>
<input type="hidden" name="token" value="${token}"/>
用戶名:<input type="text" name="username">
<input type="submit" value="提交">
</form>
</body>
</html>
業務處理
protected void doPost(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");
//一、若是用戶提交的表單數據中沒有token,則用戶是重複提交了表單
if(client_token==null){
return true;
}
//取出存儲在Session中的token
String server_token = (String) request.getSession().getAttribute("token");
//二、若是當前用戶的Session中不存在Token(令牌),則用戶是重複提交了表單
if(server_token==null){
return true;
}
//三、存儲在Session中的Token(令牌)與表單提交的Token(令牌)不一樣,則用戶是重複提交了表單
if(!client_token.equals(server_token)){
return true;
}
return false;
}
服務器端保存:
protected 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);//在服務器端保存
request.getRequestDispatcher("/form.jsp").forward(request, response);
}
生成token的工具類:
/* * 生成Token的工具類 */public class TokenProccessor { /* * 單例設計模式(保證類的對象在內存中只有一個) * 1:把類的構造函數私有 * 2:本身建立一個類的對象 * 3:對外提供一個公共的方法,返回類的對象 */ private TokenProccessor(){} private static final TokenProccessor instance = new TokenProccessor(); public static TokenProccessor getInstance(){ return instance; } 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); } }}