防重复提交:自定义注解 + AOP(@Aspect)切面

防重复提交:自定义注解 + AOP(@Aspect)切面

一、思路:

1、自定义注解;

2、创建切面类;

二、代码示例:

1、自定义注解;

import java.lang.annotation.*;

/**
 * @ClassName Resubmit
 * @Descripition 自定义注解-防重复提交
 * @Author
 * @Date 2023/8/31 10:38
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Resubmit {

    /**
     * 默认过期时间
     * 单位:秒
     *
     * @return
     */
    int value() default 100;

    /**
     * 频繁请求提示语
     *
     * @return
     */
    String messge() default "请求过于频繁,请稍后再试!";

}

2、创建切面类;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName ResubmitAspectUtil
 * @Descripition 防重复提交切面类
 * @Author
 * @Date 2023/8/31 410:52
 */
@Slf4j
@Aspect
@Component
public class ResubmitAspectUtiltest {

    @Autowired
    private StringRedisTemplate redisTemplate;

    // key: 固定前缀
    private static final String FIXED_KEY = "repeat:data:";

    // 切入点(注入自定义注解)
    @Pointcut("@annotation(Resubmit)")
    public void resubmitPointcut() {

    }

    /**
     * 同一接口API防重复(频繁)提交
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("resubmitPointcut()")
    public Object aroundPointcut(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();

            // 参数名称
            String[] parameterNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
            // 参数值
            Object[] values = joinPoint.getArgs();
            Map mapParam = new HashMap<>();
            for (int i = 0; i < parameterNames.length; i++) {
                mapParam.put(parameterNames[i], values[i]);
            }

            // 校验入参非空
            if (Objects.isNull(mapParam)) {
                return new RuntimeException("参数为空!");
            }

            // 解析入参获取请求id
            String param = JSON.toJSONString(mapParam.get("param"));
            log.info("[解析入参获取请求id] ResubmitInterceptorUtil.aroundPointcut param : {}", JSON.toJSONString(param));
            if (StringUtils.isBlank(param)) {
                return new RuntimeException("参数为空!");
            }

            JSONObject jsonObject = JSON.parseObject(param);
            if (Objects.isNull(jsonObject) || jsonObject.size() <= 0) {
                return new RuntimeException("参数为空!");
            }
            // 请求id(每次请求的唯一标识)
            String requestId = jsonObject.get("requestId").toString();
            if (StringUtils.isBlank(requestId)) {
                throw new RuntimeException("[解析入参获取请求id]异常!,请检查入参请求id");
            }

            // 获取自定义注解-防重复注解(@Resubmit)
            Resubmit resubmit = method.getAnnotation(Resubmit.class);
            // 默认过期时间、单位:秒
            int millis = resubmit.value();

            // String key = method.getDeclaringClass().getName() + "#" + method.getName();
            String key = method.getName() + "_requestId_" + requestId;
            // key: 固定前缀
            key = FIXED_KEY + key;
            Long expire = redisTemplate.opsForValue().getOperations().getExpire(key);
            if (expire != null && expire.compareTo(0L) >= 0) {
                throw new RuntimeException(resubmit.messge());
            }

            // 设置key:value 过期时间 单位秒
            redisTemplate.opsForValue().set(key, String.valueOf(System.currentTimeMillis()), millis, TimeUnit.SECONDS);

            return joinPoint.proceed();
        } catch (RuntimeException e) {
            log.error("【请求过于频繁,请稍后再试!!!】", e);
            throw new RuntimeException(e.getMessage());
        } catch (Exception e) {
            log.error("【拦截接口API防重复(频繁)提交异常!!!】", e);
            throw new RuntimeException(e.getMessage());
        }
    }

}

你可能感兴趣的:(java,开发语言)