1.准备好Redisson的配置类,提供RedissonClient实例

package com.ynby.mis.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;


/**
 * Redisson的配置类,提供RedissonClient实例
 *
 * @author my
 */
@Configuration
public class RedissonConfiguration {
    @Value("#{'${spring.redis.cluster.nodes}'.split(',')}")
    private List<String> nodes;

    @Value("${spring.redis.password}")
    private String password;

    @Bean
    public RedissonClient getRedissonClient() {
        Config config = new Config();
        config.useClusterServers().setPassword(password);
        //集群模式,集群节点的地址须使用“redis://”前缀,否则将会报错。
        //此例集群为3节点,各节点1主1从
        for (String node : nodes) {
            String redisNode = "redis://" + node;
            config.useClusterServers().addNodeAddress(redisNode);
        }
        return Redisson.create(config);
    }
}

锁时间–默认锁五秒,可自由配置

package com.ynby.mis.util;

import java.lang.annotation.*;

/**
 * @author xzt85
 * @description 防止重复提交
 * @date 2022/6/6 21:30
 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatCommit {
    long lockTime() default 5;
}

写一个切面

package com.ynby.mis.util;

import com.ynby.mis.config.MyException;
import com.ynby.mis.config.RedissonConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ObjectUtils;
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.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;


@Aspect
@Component
@Slf4j
/**
 * @description 防止重复提交
 * @date 2022/6/6 21:30
 */
public class NoRepeatSubmitAspect {

    private final static Logger logger = LoggerFactory.getLogger(NoRepeatSubmitAspect.class);
    @Resource
    private RedissonClient redissonClient;

    @Autowired
    private RedissonConfiguration redissonConfiguration;


    @Pointcut("@annotation(repeatSubmit)")
    public void pointcutNoRepeatSubmit(NoRepeatCommit repeatSubmit){

    }

    @Around("pointcutNoRepeatSubmit(noRepeatSubmit)")
    public Object around(ProceedingJoinPoint joinPoint, NoRepeatCommit noRepeatSubmit) throws Throwable {
        HttpServletRequest request=((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token=request.getHeader("token");
        String path=request.getServletPath();
        long lockTime=noRepeatSubmit.lockTime();
       // String key="REPEAT_SUBMIT_" + path + token;
        String key="REPEAT_SUBMIT_" + path;

        // 分布式锁
        RLock lock = redissonConfiguration.getRedissonClient().getLock(key);
        logger.info("获取锁 = {}",lock);
        // 尝试加锁,最多等待0秒,上锁以后5秒自动解锁[lockTime默认为5s, 用户可以自定义]
        boolean res = lock.tryLock(0, lockTime, TimeUnit.SECONDS);
        if(!res){
            throw  MyException.build("30001", "请勿重复提交");
        }

        Object object=joinPoint.proceed();
        return object;
    }
}

在需要防止重复提交的接口的Controller中加注解

@NoRepeatCommit(lockTime = 5)

    @PutMapping("updateMakerLevel")
    @NoRepeatCommit(lockTime = 5)
    public CommonClientResponse<Boolean> updateMakerLevel(@RequestBody Map map) throws Exception {

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐