原文地址:http://www.cnblogs.com/hdwpdx/archive/2016/03/29/5333943.html
首先,防止用戶重復(fù)提交有很多種方式,總體分為前端JS限制和后端限制,我個(gè)人認(rèn)為后端限制比較妥當(dāng)(本著能做到更優(yōu)秀得理念,舍去了前端JS限制重復(fù)提交得想法). 之前沒有做過防止用戶重復(fù)提交,所以直接百度了一大堆,竟然發(fā)現(xiàn)基本上可以歸為2到3種真正不同實(shí)現(xiàn)得代碼,文章雖然有很多,不過大部分代碼幾乎都出自同一人,原文網(wǎng)址:http://blog.icoolxue.com/submitted-by-sPRing-mvc-to-prevent-data-duplication/,想著這么多人用代碼應(yīng)該沒問題,所以該復(fù)制復(fù)制,該手建手建,終于大工搞成,但是測試得時(shí)候發(fā)現(xiàn)了一個(gè)很重要得問題,永遠(yuǎn)處于重復(fù)提交狀態(tài),我得天啊,這就很尷尬了,于是趕緊打斷點(diǎn),F(xiàn)6F6F6,終于懷疑了一行代碼,貼代碼:復(fù)制代碼 private boolean isRepeatSubmit(HttpServletRequest request) { String serverToken = (String) request.getsession(true).getAttribute("token"); if (serverToken == null) { return true; } String clinetToken = request.getParameter("token");//就是這行 NULL,永遠(yuǎn)是NULL。 if (clinetToken == null) { return true; } if (!serverToken.equals(clinetToken)) { return true; } return false; }嘿我就那了悶,怎么會(huì)接收不到值呢?肯定是頁面有問題了,頁面就只有一句話<input type="hidden" name="token" value="${token}" />我突然腦袋靈光一閃,通過name值傳值必須在form表單里才行,我全是Ajax啊,于是趕緊在傳遞參數(shù)中加上token,問題也就順利得結(jié)果了!但是我就再想,這么多人復(fù)制原文得代碼,然后發(fā)到自己得博客,難道沒有出現(xiàn)這種問題嘛?問題解決了,順便總結(jié)一下token得使用方法,切記代碼沒問題,復(fù)制需謹(jǐn)慎(該改得記得改!)首先自定義一個(gè)注解: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;}接著實(shí)現(xiàn)一個(gè)攔截器借口: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:interceptors> <!-- 配置Token攔截器,防止用戶重復(fù)提交數(shù)據(jù) --> <mvc:interceptor> <mvc:mapping path="/**"/><!--這個(gè)地方時(shí)你要攔截得路徑 我這個(gè)意思是攔截所有得URL--> <bean class="com.dinfo.interceptor.TokenInterceptor"/><!--class文件路徑改成你自己寫得攔截器路徑!! --> </mvc:interceptor></mvc:interceptors>最最最重要得一點(diǎn)一定要保證頁面和后臺token得正常傳遞!!!在需要生成token(通常是要點(diǎn)擊提交得那個(gè)頁面)得Controller中使用我們剛才自定義好得注解,貼代碼: @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"; } }只要通過這個(gè)方法跳向得頁面都是隨機(jī)生成一個(gè)token,然后再真正再提交觸發(fā)得方法上加入@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,到這里大功告成,你就可以發(fā)現(xiàn)已經(jīng)沒有辦法重復(fù)提交數(shù)據(jù)了!有問題可以隨時(shí)找我溝通。
新聞熱點(diǎn)
疑難解答