防重复提交解决方案

基于springboot切面

package com.minex.handler.aop;

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

@Target(ElementType.METHOD) // 可以标记在方法上
@Retention(RetentionPolicy.RUNTIME) // 在运行时通过反射来读取
public @interface NoRepeatSubmit {
    // 可以设置一些参数,例如过期时间等,这里简化处理
    String keyPrefix() default "v3:NoRepeatSubmit:";
    int expire() default 2; // 默认为2秒
}

 

package com.minex.handler.aop;

import cn.hutool.core.util.StrUtil;
import com.minex.common.exception.ExceptionFactory;
import com.minex.manager.RemoteCacheManager;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.data.redis.core.RedisTemplate;
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.Objects;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class NoRepeatSubmitAspect {

    @Resource
    private RemoteCacheManager remoteCacheManager;

    @Resource
    public RedisTemplate redisTemplate;

    @Around("@annotation(noRepeatSubmit)")
    public Object around(ProceedingJoinPoint point, NoRepeatSubmit noRepeatSubmit) throws Throwable {
        return handleCheck(point, noRepeatSubmit);
    }

    private Object handleCheck(ProceedingJoinPoint point, NoRepeatSubmit noRepeatSubmit) throws Throwable {
        String keyPrefix = noRepeatSubmit.keyPrefix();
        Integer expire = noRepeatSubmit.expire();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        // 构建key,可以根据实际情况设计,这里简单使用请求URL和请求方法作为key
        String key = buildKey(keyPrefix, request);
        // 检查Redis中是否存在该key
        boolean exists = redisTemplate.hasKey(key);
        if (!exists) {
            remoteCacheManager.setCacheObject(key, "1", expire, TimeUnit.SECONDS);
            // 如果key不存在,则认为是有效请求,继续执行
            return point.proceed();
        } else {
            // 如果key已存在,则认为是重复请求 并且刷新过期时间
            remoteCacheManager.expire(key, expire, TimeUnit.SECONDS);
            throw ExceptionFactory.bizException("请勿重复提交," + expire + "秒内不能重复提交");
        }
    }

    private String buildKey(String prefix, HttpServletRequest request) {
        // 根据实际情况构建key,这里以请求的URL和HTTP方法为基础
        String uri = request.getRequestURI();
        String method = request.getMethod();
        String token = request.getHeader("authorization");
        if (StrUtil.isNotEmpty(token)) {
            return prefix + ":" + uri + ":" + method + ":" + token;
        } else {
            return prefix + ":" + uri + ":" + method;
        }
    }
}

 

使用示例

 

posted @ 2024-11-14 17:20  官萧何  阅读(4)  评论(0编辑  收藏  举报