最近開發項目時候發現,有時候由於網絡或者我的問題,會出現重複點擊提交按鈕的狀況,這樣有可能會在數據庫生成兩條數據,形成數據混淆。今天來談一下如何解決這個問題。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>29.0-jre</version> </dependency>
/** * 返回信息 * * @author zhouzhaodong */ public class RestMessage { private int code; private String message; private Object data; public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public RestMessage(int code, String message, Object data) { this.code = code; this.message = message; this.data = data; } public RestMessage(int code, String message) { this.code = code; this.message = message; } }
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 定義一個註解 * @apiNote @Target(ElementType.METHOD) 做用到方法上 * @apiNote @Retention(RetentionPolicy.RUNTIME) 只有運行時有效 * @author zhouzhaodong */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface NoRepeatSubmit { }
import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.context.annotation.Configuration; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.util.Objects; import java.util.concurrent.TimeUnit; /** * 自定義一個切面類,利用aspect實現切入全部方法 * * @author zhouzhaodong */ @Aspect @Configuration public class NoRepeatSubmitAop { private final Log logger = LogFactory.getLog(getClass()); /** * 重複提交判斷時間爲2s */ private final Cache<String, Integer> cache = CacheBuilder.newBuilder().expireAfterWrite(2L, TimeUnit.SECONDS).build(); @Around("execution(* xyz.zhouzhaodong..*Controller.*(..)) && @annotation(nrs)") public Object around(ProceedingJoinPoint pjp, NoRepeatSubmit nrs) { try { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); String sessionId = Objects.requireNonNull(RequestContextHolder.getRequestAttributes()).getSessionId(); assert attributes != null; HttpServletRequest request = attributes.getRequest(); String key = sessionId + "-" + request.getServletPath(); // 若是緩存中有這個url視爲重複提交 if (cache.getIfPresent(key) == null) { Object o = pjp.proceed(); cache.put(key, 0); return o; } else { logger.error("重複提交"); return new RestMessage(888, "請勿短期內重複操做"); } } catch (Throwable e) { e.printStackTrace(); logger.error("驗證重複提交時出現未知異常!"); return new RestMessage(889, "驗證重複提交時出現未知異常!"); } } }
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * 測試 * @author zhouzhaodong */ @RestController @RequestMapping("/test") public class TestController { /** * 添加防重複提交註解 * @return */ @NoRepeatSubmit @RequestMapping("/one") public RestMessage test(){ return new RestMessage(0, "測試經過"); } }
第一次點擊返回正常信息:
快速點擊第二次會出現錯誤信息:
java
測試經過!git
https://github.com/zhouzhaodo...github