傳統方式(不推薦)
首先我們介紹下之前傳統的防重複提交方式:
1:前端處理:
思路如下:
function dosubmit(){
//第一步,我們需要獲取表單的提交按鈕。
var btnSubmit = document.getElementById("submit");
//第二步,需要將表單提交按鈕設置爲不可用(或則直接隱藏,但是隱藏的話會被認爲是BUG),這樣就可以避免用戶再次點擊提交按鈕,進行提交操作。
btnSubmit.disabled= "disabled";
//第三步,返回true讓表單可以正常提交。
return true;
}
2:服務端session處理
思路如下:
1、在服務器端生成一個唯一的隨機標識號,專業術語稱爲Token(令牌),並在當前用戶的Session域中保存這個Token。
2、將Token發送到客戶端的Form表單中,在Form表單中使用隱藏域來存儲這個Token,表單提交的時候連同這個Token一起提交到服務器端。
3、在服務器端判斷客戶端提交上來的Token與服務器端生成的Token是否一致,如果不一致,那就是重複提交了,此時服務器端就可以不處理重複提交的表單。如果相同則處理表單提交,處理完後清除當前用戶的Session域中存儲的標識號。
Spring-AOP防重解決方案(推薦)
以上是比較早的防重複提交解決方案,本文我們再介紹一種:
服務端Spring -AOP防重
思路如下:
1、自定義註解 @NoRepeatSubmit 標記有必要防重複提交請求Controller。
2、通過Spring-AOP方式對所有標記了 @NoRepeatSubmit 的方法進行切入攔截。
3、在業務方法執行前,獲取當前用戶的 token+ 當前請求地址,作爲一個唯一 KEY,去獲取 Redis 分佈式鎖(如果此時併發獲取,只有一個線程會被成功獲取到鎖)。
4、業務方法執行後,一定要釋放鎖,異常也要釋放鎖(放到finally中釋放亦可)。
通過上面測試,我們看到初始化十個線程,只有一個線程是提交成功了。