search
HomeDatabaseRedisHow SpringBoot combines Aop+Redis to prevent repeated submission of interfaces

In actual development projects, an externally exposed interface often faces many requests. Let us explain the concept of idempotence: The impact of any multiple executions is the same as the impact of one execution. According to this meaning, the final meaning is that the impact on the database can only be one-time and cannot be processed repeatedly. How to ensure its idempotence usually involves the following methods:

1. Establish a unique index in the database to ensure that only one piece of data is ultimately inserted into the database.

2. Token mechanism. Obtain a token before each interface request, and then add this token to the header body of the request the next time. Verification is performed in the background. If the verification passes, the token is deleted. Next The token is judged again for each request.

3. Pessimistic lock or optimistic lock. Pessimistic lock can ensure that other SQL cannot update data every time for update (when the database engine is innodb, the select condition must be a unique index to prevent the entire table from being locked. )

4. Query first and then judge. First, query the database to see if the data exists. If it exists, it proves that the request has been made, and the request is directly rejected. If it does not exist, it proves that it is the first time to come in, and it is directly released.

Why should we prevent repeated submission of interfaces?
For some sensitive operation interfaces, such as new data interfaces and payment interfaces, if the user improperly clicks the submit button multiple times, these interfaces will be requested multiple times, which may eventually lead to system exceptions.

How can the front end be controlled?
The front end can be controlled through js. When the user clicks the submit button,
1. Set the button to be unclickable for a number of seconds.
2. After the button is clicked, a loading prompt box will pop up to avoid clicking again until the interface request returns. After
3. Click the button to jump to a new page

However, please remember, never trust the user’s behavior, because you don’t know what weird operations the user will do, so the most important thing is It still has to be processed on the back end.

Use aop redis for interception processing
1. Create the aspect class RepeatSubmitAspect
Implementation process: After the interface request, the token request path is used as the key value to read data from redis. If the key can be found, It proves that it was submitted repeatedly, and vice versa. If it is not a repeated submission, it will be released directly, and the key will be written into redis, and set to expire within a certain period of time (I set an expiration of 5s here)


In traditional web projects, in order to prevent For repeated submissions, the usual approach is: the backend generates a unique submission token (uuid) and stores it on the server. When the page initiates a request, it carries the secondary token. The backend deletes the token after verifying the request to ensure the uniqueness of the request.
However, the appeal method requires changes to both the front and back ends. If it is in the early stage of the project, it can be achieved. However, in the later stage of the project, many functions have been implemented and it is impossible to make large-scale changes.

Ideas
1. Customize the annotation @NoRepeatSubmit to mark all requests submitted in the Controller
2. Intercept all methods marked with @NoRepeatSubmit through AOP
3. Execute the business method Before, obtain the current user's token or JSessionId current request address as a unique key to obtain the redis distributed lock. If concurrent acquisition is performed at this time, only one thread can obtain it.
4. After the business is executed, release the lock

About Redis distributed lock
Using Redis is for load balancing deployment. If it is a stand-alone project, you can use a local thread-safe Cache to replace Redis

Code
Custom annotation

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

/**
 * @ClassName NoRepeatSubmit
 * @Description 这里描述
 * @Author admin
 * @Date 2021/3/2 16:16
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatSubmit {

    /**
     * 设置请求锁定时间
     *
     * @return
     */
    int lockTime() default 10;

}

AOP

package com.hongkun.aop;

/**
 * @ClassName RepeatSubmitAspect
 * @Description 这里描述
 * @Author admin
 * @Date 2021/3/2 16:15
 */

import com.hongkun.until.ApiResult;
import com.hongkun.until.Result;
import com.hongkun.until.RedisLock;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author liucheng
 * @since 2020/01/15
 * 防止接口重复提交
 */
@Aspect
@Component
public class RepeatSubmitAspect {
    private static final Logger LOGGER = LoggerFactory.getLogger(RepeatSubmitAspect.class);

    @Autowired
    private RedisLock redisLock;

    @Pointcut("@annotation(noRepeatSubmit)")
    public void pointCut(NoRepeatSubmit noRepeatSubmit) {
    }

    @Around("pointCut(noRepeatSubmit)")
    public Object around(ProceedingJoinPoint pjp, NoRepeatSubmit noRepeatSubmit) throws Throwable {

        int lockSeconds = noRepeatSubmit.lockTime();

        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();

        Assert.notNull(request, "request can not null");

        // 此处可以用token或者JSessionId
        String token = request.getHeader("token");
        String path = request.getServletPath();
        String key = getKey(token, path);
        String clientId = getClientId();

        boolean isSuccess = redisLock.lock(key, clientId, lockSeconds,TimeUnit.SECONDS);
        LOGGER.info("tryLock key = [{}], clientId = [{}]", key, clientId);

        if (isSuccess) {
            LOGGER.info("tryLock success, key = [{}], clientId = [{}]", key, clientId);
            // 获取锁成功
            Object result;
            try {
                // 执行进程
                result = pjp.proceed();
            } finally {
                // 解锁
                redisLock.unlock(key, clientId);
                LOGGER.info("releaseLock success, key = [{}], clientId = [{}]", key, clientId);
            }

            return result;

        } else {
            // 获取锁失败,认为是重复提交的请求
            LOGGER.info("tryLock fail, key = [{}]", key);
            return ApiResult.success(200, "重复请求,请稍后再试", null);
        }

    }

    private String getKey(String token, String path) {
        return "00000"+":"+token + path;
    }

    private String getClientId() {
        return UUID.randomUUID().toString();
    }


}

The above is the detailed content of How SpringBoot combines Aop+Redis to prevent repeated submission of interfaces. For more information, please follow other related articles on the PHP Chinese website!

Statement
This article is reproduced at:亿速云. If there is any infringement, please contact admin@php.cn delete
Redis: Beyond SQL - The NoSQL PerspectiveRedis: Beyond SQL - The NoSQL PerspectiveMay 08, 2025 am 12:25 AM

Redis goes beyond SQL databases because of its high performance and flexibility. 1) Redis achieves extremely fast read and write speed through memory storage. 2) It supports a variety of data structures, such as lists and collections, suitable for complex data processing. 3) Single-threaded model simplifies development, but high concurrency may become a bottleneck.

Redis: A Comparison to Traditional Database ServersRedis: A Comparison to Traditional Database ServersMay 07, 2025 am 12:09 AM

Redis is superior to traditional databases in high concurrency and low latency scenarios, but is not suitable for complex queries and transaction processing. 1.Redis uses memory storage, fast read and write speed, suitable for high concurrency and low latency requirements. 2. Traditional databases are based on disk, support complex queries and transaction processing, and have strong data consistency and persistence. 3. Redis is suitable as a supplement or substitute for traditional databases, but it needs to be selected according to specific business needs.

Redis: Introduction to a Powerful In-Memory Data StoreRedis: Introduction to a Powerful In-Memory Data StoreMay 06, 2025 am 12:08 AM

Redisisahigh-performancein-memorydatastructurestorethatexcelsinspeedandversatility.1)Itsupportsvariousdatastructureslikestrings,lists,andsets.2)Redisisanin-memorydatabasewithpersistenceoptions,ensuringfastperformanceanddatasafety.3)Itoffersatomicoper

Is Redis Primarily a Database?Is Redis Primarily a Database?May 05, 2025 am 12:07 AM

Redis is primarily a database, but it is more than just a database. 1. As a database, Redis supports persistence and is suitable for high-performance needs. 2. As a cache, Redis improves application response speed. 3. As a message broker, Redis supports publish-subscribe mode, suitable for real-time communication.

Redis: Database, Server, or Something Else?Redis: Database, Server, or Something Else?May 04, 2025 am 12:08 AM

Redisisamultifacetedtoolthatservesasadatabase,server,andmore.Itfunctionsasanin-memorydatastructurestore,supportsvariousdatastructures,andcanbeusedasacache,messagebroker,sessionstorage,andfordistributedlocking.

Redis: Unveiling Its Purpose and Key ApplicationsRedis: Unveiling Its Purpose and Key ApplicationsMay 03, 2025 am 12:11 AM

Redisisanopen-source,in-memorydatastructurestoreusedasadatabase,cache,andmessagebroker,excellinginspeedandversatility.Itiswidelyusedforcaching,real-timeanalytics,sessionmanagement,andleaderboardsduetoitssupportforvariousdatastructuresandfastdataacces

Redis: A Guide to Key-Value Data StoresRedis: A Guide to Key-Value Data StoresMay 02, 2025 am 12:10 AM

Redis is an open source memory data structure storage used as a database, cache and message broker, suitable for scenarios where fast response and high concurrency are required. 1.Redis uses memory to store data and provides microsecond read and write speed. 2. It supports a variety of data structures, such as strings, lists, collections, etc. 3. Redis realizes data persistence through RDB and AOF mechanisms. 4. Use single-threaded model and multiplexing technology to handle requests efficiently. 5. Performance optimization strategies include LRU algorithm and cluster mode.

Redis: Caching, Session Management, and MoreRedis: Caching, Session Management, and MoreMay 01, 2025 am 12:03 AM

Redis's functions mainly include cache, session management and other functions: 1) The cache function stores data through memory to improve reading speed, and is suitable for high-frequency access scenarios such as e-commerce websites; 2) The session management function shares session data in a distributed system and automatically cleans it through an expiration time mechanism; 3) Other functions such as publish-subscribe mode, distributed locks and counters, suitable for real-time message push and multi-threaded systems and other scenarios.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

SecLists

SecLists

SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Powerful PHP integrated development environment

MantisBT

MantisBT

Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version