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.使用的包
来源:oschina
链接:https://my.oschina.net/u/4365009/blog/4273390