最近开发项目时候发现,有时候因为网络或者个人问题,会出现重复点击提交按钮的情况,这样有可能会在数据库生成两条数据,造成数据混淆。今天来谈一下如何解决这个问题。

搭建springboot项目

1. 选择新建项目

2. 选择Spring Initializr

3. 填写相关信息

4. 选择web依赖

5. 选择项目位置

开始代码书写啦

1. pom.xml文件依赖添加

<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>

2. 定义一个异常类

/** * 返回信息 * * @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;    }}

3. 定义一个接口

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 {}

4. 定义一个切面

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@Configurationpublic 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, "验证重复提交时出现未知异常!");        }    }}

5. 写controller进行测试

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, "测试通过");    }}

第一次点击返回正常信息:

快速点击第二次会出现错误信息:

测试通过!

源代码地址为:

https://github.com/zhouzhaodo...

个人博客地址:

http://www.zhouzhaodong.xyz/