spring Aop實現防止重複提交

1.先定義一個註解

import java.lang.annotation.*;

/**
 * @desc 定義一個不重複提交的註解
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NoRepeatCommit {

    String name() default "name:";
}

 

2.實現一個aop

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
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.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

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

import javassist.*;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

/**
 * @desc 防止重複提交aop
 */
@EnableAspectJAutoProxy
@Component
@Aspect
@Slf4j
@Configuration
public class NoRepeatSubmitAspect {

    private static final Cache<String, Object> CACHES = CacheBuilder.newBuilder()
            // 最大緩存 100 個
            .maximumSize(100)
            // 設置緩存過期時間爲S
            .expireAfterWrite(2, TimeUnit.SECONDS)
            .build();

    @Pointcut("@annotation(com.shandie.im.web.aop.NoRepeatCommit)")
    public void point() {
    }

    @Around("point()")
    public Object interceptor(ProceedingJoinPoint pjp) {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        NoRepeatCommit form = method.getAnnotation(NoRepeatCommit.class);
        String key = getCacheKey(method,pjp,form);

        if (!StringUtils.isEmpty(key)) {
            if (CACHES.getIfPresent(key) != null) {
                return RestResultDto.fail("請勿重複請求");
            }
            // 如果是第一次請求,就將key存入緩存中
            CACHES.put(key, key);
        }
        try {
            return pjp.proceed();
        } catch (Throwable throwable) {
            throw new RuntimeException("服務器開小差了,請稍後再試");
        } finally {
            CACHES.invalidate(key);
        }
    }

    /**
     * 緩存key生成方式
     * @param method
     * @param pjp
     * @param form
     * @return
     */
    private String getCacheKey(Method method, ProceedingJoinPoint pjp, NoRepeatCommit form) {
        try{
            Map<String, Object> map=getFieldsNameValueMap(pjp);
            if(ObjectHelper.isNotEmpty(map) && map.size()>0){
                HpBaseDto baseDto= JSON.parseObject(JSON.toJSONString(map),HpBaseDto.class);
                if(ObjectHelper.isNotEmpty(baseDto) && ObjectHelper.isNotEmpty(baseDto.getUserId())){
                    return form.name()+baseDto.getUserId();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return form.name()+ CustomIDGenerator.generate();
    }

    public static Map<String, Object> getFieldsNameValueMap(ProceedingJoinPoint joinPoint) throws Exception {
        Object[] args = joinPoint.getArgs();
        String classType = joinPoint.getTarget().getClass().getName();
        Class<?> clazz = Class.forName(classType);
        String clazzName = clazz.getName();
        //獲取方法名稱
        String methodName = joinPoint.getSignature().getName();
        Map<String, Object> map = Maps.newHashMap();
        ClassPool pool = ClassPool.getDefault();
        ClassClassPath classPath = new ClassClassPath(NoRepeatCommit.class);
        pool.insertClassPath(classPath);
        CtClass cc = pool.get(clazzName);
        CtMethod cm = cc.getDeclaredMethod(methodName);
        MethodInfo methodInfo = cm.getMethodInfo();
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        if (attr == null) {
            throw new RuntimeException();
        }
        int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
        //paramNames即參數名
        for (int i = 0; i < cm.getParameterTypes().length; i++) {
            map.put(attr.variableName(i + pos), args[i]);
        }
        return map;
    }
}

 

3.使用

 @PostMapping("/test")
    @NoRepeatCommit
    public RestResultDto aa(){
        return RestResultDto.success("success");
    }

 

4.使用的包

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章