SpringBoot防止重複請求,重複表單提交超級簡單的註解實現之四(終極版)
阿新 • • 發佈:2019-01-02
前言:上篇文章有的童鞋說不行啊,怎麼不能防止重複提交呢!
首先需要說明的是之前的防止重複提交是指:一次請求完成之前防止重複提交,當然擴充套件下就可以做到會話間防止重複提交,還可以擴充套件為某個時間段或者永久防止重複提交(這個我就不實現了),下面我來擴充套件一下相同會話防止重複提交其實很簡單
在上一篇的基礎上DuplicateAspect不移除標記為SESSION的token就可以了!
1.DuplicateSubmitToken.java新增屬性type,預設為一次請求完成之前防止重複提交
/** * @description 防止表單重複提交註解 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface DuplicateSubmitToken { /**一次請求完成之前防止重複提交*/ public static final int REQUEST=1; /**一次會話中防止重複提交*/ public static final int SESSION=2; /**儲存重複提交標記 預設為需要儲存*/ boolean save() default true; /**防止重複提交型別,預設:一次請求完成之前防止重複提交*/ int type() default REQUEST; }
2.DuplicateSubmitAspect.java方法doAfterReturing判斷如果REQUEST才移除防止重複提交,因為SESSION標記在會話結束 時或失效時會自動移除標記
/** * @description 防止表單重複提交攔截器 */ @Aspect @Component @Slf4j public class DuplicateSubmitAspect { public static final String DUPLICATE_TOKEN_KEY="duplicate_token_key"; @Pointcut("execution(public * cn.test.controller..*(..))") public void webLog() { } @Before("webLog() && @annotation(token)") public void before(final JoinPoint joinPoint, DuplicateSubmitToken token){ if (token!=null){ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); boolean isSaveSession=token.save(); if (isSaveSession){ String key = getDuplicateTokenKey(joinPoint); Object t = request.getSession().getAttribute(key); if (null==t){ String uuid= UUID.randomUUID().toString(); request.getSession().setAttribute(key.toString(),uuid); log.info("token-key="+key); log.info("token-value="+uuid.toString()); }else { throw new DuplicateSubmitException(TextConstants.REQUEST_REPEAT); } } } } /** * 獲取重複提交key * @param joinPoint * @return */ public String getDuplicateTokenKey(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); StringBuilder key=new StringBuilder(DUPLICATE_TOKEN_KEY); key.append(",").append(methodName); return key.toString(); } @AfterReturning("webLog() && @annotation(token)") public void doAfterReturning(JoinPoint joinPoint,DuplicateSubmitToken token) { // 處理完請求,返回內容 log.info("出方法:"); if (token!=null){ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); boolean isSaveSession=token.save(); if (isSaveSession){ String key = getDuplicateTokenKey(joinPoint); Object t = request.getSession().getAttribute(key); if (null!=t&&token.type()==DuplicateSubmitToken.REQUEST){ request.getSession(false).removeAttribute(key); } } } } /** * 異常 * @param joinPoint * @param e */ @AfterThrowing(pointcut = "webLog()&& @annotation(token)", throwing = "e") public void doAfterThrowing(JoinPoint joinPoint, Throwable e, DuplicateSubmitToken token) { if (null!=token && e instanceof DuplicateSubmitException==false){ //處理處理重複提交本身之外的異常 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); boolean isSaveSession=token.save(); //獲得方法名稱 if (isSaveSession){ String key=getDuplicateTokenKey(joinPoint); Object t = request.getSession().getAttribute(key); if (null!=t){ //方法執行完畢移除請求重複標記 request.getSession(false).removeAttribute(key); log.info("異常情況--移除標記!"); } } } } }
3.使用標記為會話防止重複提交
/** * @description */ @RestController public class TestController { @DuplicateSubmitToken(type = DuplicateSubmitToken.SESSION) @RequestMapping(value = "/test/d", method = RequestMethod.GET) public Map<String, Object> test (HttpServletRequest request){ Random r=new Random(); int i = r.nextInt(3); if (i==2){ throw new CustomException("有異常"); } try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } Map<String, Object> map = new HashMap<>(); request.getSession().setAttribute("request Url", request.getRequestURL()); map.put("request Url", request.getRequestURL()); return map; } }
4.做了這些可能還是會遇到資料重複插入問題
我們可以根據給建立唯一索引給某個欄位,防止資料不重複插入,或者給方法加鎖(同步)
作者:天空藍藍的
版權所有,歡迎保留原文連結進行轉載:)