Personal learning series – springboot prevent duplicate submission

Time:2021-5-2

Recently, when developing a project, I found that sometimes, due to network or personal problems, there will be repeated clicks on the submit button, which may generate two pieces of data in the database, causing data confusion. Today, let’s talk about how to solve this problem.

Build spring boot project

1. Select a new project

Personal learning series - springboot prevent duplicate submission

2. Select spring initializer

Personal learning series - springboot prevent duplicate submission

3. Fill in the relevant information

Personal learning series - springboot prevent duplicate submission

4. Select web dependency

Personal learning series - springboot prevent duplicate submission

5. Select project location

Personal learning series - springboot prevent duplicate submission

Start coding

1. Add pom.xml file dependency

<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. Define an exception class

/**
 *Return information
 *
 * @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. Define an interface

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 *Define an annotation
 *@ apinote @ target (ElementType. Method) is applied to the method
 *@ apinote @ retention (retentionpolicy. Runtime) is only valid at runtime
 * @author zhouzhaodong
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatSubmit {

}

4. Define a section

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;

/**
 *Customize a section class and use aspect to implement all methods
 *
 * @author zhouzhaodong
 */
@Aspect
@Configuration
public class NoRepeatSubmitAop {

    private final Log logger = LogFactory.getLog(getClass());

    /**
     *The judgment time of repeated submission is 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();
            //If there is this URL in the cache, it is regarded as a duplicate submission
            if (cache.getIfPresent(key) == null) {
                Object o = pjp.proceed();
                cache.put(key, 0);
                return o;
            } else {
                Logger. Error ("duplicate submission");
                Return new restmessage (888, "do not repeat the operation in a short time");
            }
        } catch (Throwable e) {
            e.printStackTrace();
            Logger. Error ("unknown exception occurred when verifying duplicate commit!");
            Return new restmessage (889, "unknown exception occurred when verifying duplicate submission!");
        }

    }

}

5. Write controller to test

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 *Testing
 * @author zhouzhaodong
 */
@RestController
@RequestMapping("/test")
public class TestController {

    /**
     *Add anti duplicate submission comments
     * @return
     */
    @NoRepeatSubmit
    @RequestMapping("/one")
    public RestMessage test(){
        Return new restmessage (0, "test passed");
    }

}

First click to return to normal information:
Personal learning series - springboot prevent duplicate submission
If you click the second time quickly, an error message will appear:
Personal learning series - springboot prevent duplicate submission

Test passed!

The source code address is:

https://github.com/zhouzhaodo…

Personal blog address:

http://www.zhouzhaodong.xyz/

Recommended Today

Hot! Front and rear learning routes of GitHub target 144K

Hello, Sifu’s little friend. I’m silent Wang Er. Last week, while appreciating teacher Ruan Yifeng’s science and technology weekly, I found a powerful learning route, which has been marked with 144K on GitHub. It’s very popular. It covers not only the front-end and back-end learning routes, but also the operation and maintenance learning routes. As […]