spring Aop实现防止重复提交
Posted 全力以赴001
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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.使用的包
以上是关于spring Aop实现防止重复提交的主要内容,如果未能解决你的问题,请参考以下文章
Spring Cloud项目如何防止重复提交,防重复提交幂等校验,Redis+aop+自定义Annotation实现接口