package com.doumee.api.Repeat; import com.doumee.core.constants.ResponseStatus; import com.doumee.core.exception.BusinessException; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; 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.lang.reflect.Method; import java.util.concurrent.TimeUnit; // 开启日志,需要依赖lombok @Slf4j // 把一个类定义为切面供容器读取 @Aspect @Component public class RepeatSubmitAspect { @Resource private RedisTemplate redisTemplate; // 这是一个环绕通知,它会围绕被 @RepeatSubmit 注解标记的方法执行,这里的 repeatSubmit 与下面的参数对应 @Around("@annotation(repeatSubmit)") public Object around(ProceedingJoinPoint point, RepeatSubmit repeatSubmit) throws Throwable { // 获取用户的token验证,这里项目用的是 header 里的 Authorization 参数 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String requestToken = request.getHeader("token"); // 获取注解 MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); // 获取类,方法 String className = method.getDeclaringClass().getName(); String methodName = method.getName(); // 组装key:用户唯一标识+操作类+方法 String key = requestToken + "#" + className + "#" + methodName; String keyHashCode = String.valueOf(Math.abs(key.hashCode())); log.info("key:{},keyHashcode:{}", key, keyHashCode); //获取超时时间 int timeOut = repeatSubmit.timeout(); log.info("超时时间{}", timeOut); // 从缓存给中根据key获取数据 String value = redisTemplate.opsForValue().get(keyHashCode); if (value != null) { log.info("重复提交"); // 如果value不为空; return "请勿重复提交"; throw new BusinessException(ResponseStatus.MASSIVE_REQUEST); } else { log.info("首次提交"); // value为空,则加入缓存,并设置过期过期时间 redisTemplate.opsForValue().set(keyHashCode, "1", timeOut, TimeUnit.MILLISECONDS); } //执行Object Object object = point.proceed(); return object; } }