首先,防止用戶重複提交有不少種方式,整體分爲前端JS限制和後端限制,我我的認爲後端限制比較穩當(本着能作到更優秀得理念,捨去了前端JS限制重複提交得想法).前端
以前沒有作過防止用戶重複提交,因此直接百度了一大堆,居然發現基本上能夠歸爲2到3種真正不一樣實現得代碼,文章雖然有不少,不過大部分代碼幾乎都出自同一人,原文網址:http://blog.icoolxue.com/submitted-by-spring-mvc-to-prevent-data-duplication/,想着這麼多人用代碼應該沒問題,因此該複製複製,該手建手建,終於大工搞成,可是測試得時候發現了一個很重要得問題,永遠處於重複提交狀態,我得天啊,這就很尷尬了,因而趕忙打斷點,F6F6F6,終於懷疑了一行代碼,貼代碼:java
private boolean isRepeatSubmit(HttpServletRequest request) { String serverToken = (String) request.getSession(true).getAttribute("token"); if (serverToken == null) { return true; } String clinetToken = request.getParameter("token");//就是這行 NULL,永遠是NULL。 if (clinetToken == null) { return true; } if (!serverToken.equals(clinetToken)) { return true; } return false; }
嘿我就那了悶,怎麼會接收不到值呢?確定是頁面有問題了,頁面就只有一句話
<input type="hidden" name="token" value="${token}" />
我忽然腦殼靈光一閃,經過name值傳值必須在form表單裏才行,我全是AJAX啊,因而趕忙在傳遞參數中加上token,問題也就順利得結果了!web
可是我就再想,這麼多人複製原文得代碼,而後發到本身得博客,難道沒有出現這種問題嘛?spring
問題解決了,順便總結一下token得使用方法,切記代碼沒問題,複製需謹慎(該改得記得改!)apache
首先自定義一個註解:後端
package com.dinfo.interceptor; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Token { boolean save() default false; boolean remove() default false; }
接着實現一個攔截器藉口:spring-mvc
package com.dinfo.interceptor; import java.lang.reflect.Method; import java.util.UUID; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; public class TokenInterceptor extends HandlerInterceptorAdapter { private static final Logger LOG = Logger.getLogger(Token.class); @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(true).setAttribute("token", UUID.randomUUID().toString()); } boolean needRemoveSession = annotation.remove(); if (needRemoveSession) { if (isRepeatSubmit(request)) { LOG.warn("please don't repeat submit,url:"+ request.getServletPath()); return false; } request.getSession(true).removeAttribute("token"); } } return true; } else { return super.preHandle(request, response, handler); } } private boolean isRepeatSubmit(HttpServletRequest request) { String serverToken = (String) request.getSession(true).getAttribute("token"); if (serverToken == null) { return true; } String clinetToken = request.getParameter("token"); if (clinetToken == null) { return true; } if (!serverToken.equals(clinetToken)) { return true; } return false; } }
最後是配置文件:mvc
<!-- 攔截器配置 -->
<mvc:interceptors>
<!-- 配置Token攔截器,防止用戶重複提交數據 -->
<mvc:interceptor>
<mvc:mapping path="/**"/><!--這個地方時你要攔截得路徑 我這個意思是攔截全部得URL-->
<bean class="com.dinfo.interceptor.TokenInterceptor"/><!--class文件路徑改爲你本身寫得攔截器路徑!! -->
</mvc:interceptor>
</mvc:interceptors>
最最最重要得一點必定要保證頁面和後臺token得正常傳遞!!!app
在須要生成token(一般是要點擊提交得那個頁面)得Controller中使用咱們剛纔自定義好得註解,貼代碼:dom
@SuppressWarnings({ "unchecked", "finally", "rawtypes" }) @RequestMapping("/SaveDataController/show") @Token(save=true) public String saveData(HttpServletRequest request,HttpServletResponse response,String task_id){ Map map = new HashMap(); System.out.println(task_id); try { map = saveDataService.queryByTaskId(task_id); } catch (Exception e) { e.printStackTrace(); map.put("task_id", task_id); map.put("savetype", ""); map.put("memoryCodes", "1"); map.put("tablename", ""); map.put("trowkey", ""); map.put("columns", ""); map.put("indextablename", ""); map.put("irowkey", ""); map.put("icolumns", ""); } finally { request.setAttribute("map", map); return "savedata/index"; } }
只要經過這個方法跳向得頁面都是隨機生成一個token,而後再真正再提交觸發得方法上加入@token(remove=true),貼代碼:
@RequestMapping("/SaveDataController/saveData") @ResponseBody @Token(remove=true) public void saveData(HttpServletRequest request,HttpServletResponse response, String tablename,String trowkey,String columns, String indextablename,String irowkey,String icolumns, String task_id,String savetype,String memoryCodes){ System.out.println(task_id); saveDataService.saveData(task_id,savetype,memoryCodes,tablename, trowkey, columns, indextablename, irowkey, icolumns); }
OK,到這裏大功告成,你就能夠發現已經沒有辦法重複提交數據了!有問題能夠隨時找我溝通。