在平時開發中,若是網速比較慢的狀況下, 用戶提交表單後,發現服務器半天沒有響應,用戶可能覺得是本身沒有提交表單,就會再點擊提交按鈕重複提交表單,因此在開發中咱們須要防止表單重複提交javascript
在網絡延遲的狀況下讓用戶有時間點擊屢次submit致使表單重複提交html
表單提交後用戶點擊 刷新按鈕致使表單重複提交java
用戶提交表單後,點擊後退按鈕回退到表單頁面後進行再次提交spring
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML> <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; }
在服務器端生成一個惟一的隨機標識號,稱爲Token(令牌),同時在當前用戶的Session域中保存這個Token。而後將Token發送到客戶端的Form表單中,在Form表單中使用隱藏域來存儲這個Token,表單提交的時候連同這個Token一塊兒提交到服務器端,而後在服務器端判斷客戶端提交上來的Token與服務器端生成的Token是否一致,若是不一致,那就是重複提交了,此時服務器端就能夠不處理重複提交的表單。若是相同則處理表單提交,處理完後清除當前用戶的Session域中存儲的標識號。網絡
定義Token代碼:mvc
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Token { boolean save() default false; boolean remove() default false; }
定義攔截器TokenInterceptor:app
public class TokenInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); Token annotation = method.getAnnotation(Token.class); if (annotation != null) { boolean needSaveSession = annotation.save(); if (needSaveSession) { request.getSession(false).setAttribute("token", UUID.randomUUID().toString()); } boolean needRemoveSession = annotation.remove(); if (needRemoveSession) { if (isRepeatSubmit(request)) { return false; } request.getSession(false).removeAttribute("token"); } } return true; } else { return super.preHandle(request, response, handler); } } private boolean isRepeatSubmit(HttpServletRequest request) { String serverToken = (String)request.getSession(false).getAttribute("token"); if (serverToken == null) { return true; } String clientToken = request.getParameter("token"); if (clientToken == null) { return true; } if(!serverToken.equals(clientToken)){ return true; } return false; } }
而後在springmvc的配置文件中加入:dom
<!--配置攔截器--> <mvc:interceptors> <!--配置token攔截器,防止用戶重複提交數據--> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.simple.interceptor.TokenInterceptor"/> </mvc:interceptor> </mvc:interceptors>
在jsp頁面form裏面添加下面的代碼:jsp
<input type="hidden" name="token" value="${token}">
使用上面在須要生成token的controller上增長@Token(save=true) ,須要檢查重複提交的controller上添加@Token(remove=true)
@RequestMapping("/save") @AvoidDuplicateSubmission(save= true) public synchronized ModelAndView save(ExecutionUnit unit, HttpServletRequest request, HttpServletResponse response) throws Exception { @RequestMapping("/edit") @AvoidDuplicateSubmission(remove= true) public ModelAndView edit(Integer id, HttpServletRequest request) throws Exception {