1. 自定义注解
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RepeatRequest { /** * 是否开启 默认false 不开启 * @return */ boolean opened() default false; /** * 等待时间 单位 秒 s * @return */ long time() default 1; }
2. 创建切面类
import cn.hutool.json.JSONUtil; import com.taurus.zjbm.common.exception.BusinessException; import com.taurus.zjbm.utils.RedisUtil; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; @Aspect @Component @Slf4j public class RepeatAspectNow { @Autowired private RedisUtil redisService; // 通过注解引入切面类 @Pointcut("@annotation(com.taurus.zjbm.common.aop.request.RepeatRequest)") private void pt() { } // 这里使用的是前置通知 @Before("pt()") public Object around(final JoinPoint joinPoint){ log.info("重复提交校验"); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); assert attributes != null; MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method1 = signature.getMethod(); RepeatRequest repeatRequest = method1.getAnnotation(RepeatRequest.class); boolean opened = repeatRequest.opened(); String[] argNames = signature.getParameterNames(); log.info("argNames" JSONUtil.toJsonStr(argNames)); if (opened) { long time = repeatRequest.time(); log.info("重复提交校验开始"); HttpServletRequest request = attributes.getRequest(); Object[] args = joinPoint.getArgs(); String url = request.getRequestURI(); String param = JSONUtil.toJsonStr(args); log.info("param:{}", param); final Map<String, String> map = new HashMap<>(1); map.put(url, param); String userId = "1"; // 如果缓存中有这个url视为重复提交 final String nowUrlParams = map.toString(); log.info("重复提交校验修改map" nowUrlParams); final String requestRepeatKey = userId.concat(url).concat("/").concat(nowUrlParams); final String msg = (String) redisService.get(requestRepeatKey); if (ObjectUtils.isEmpty(msg)) { log.info("重复提交校验修改不存在" msg); // 当前key 如果没有,请求是允许的 time = ObjectUtils.isEmpty(time) ? 1 : time; //默认200毫秒 redisService.set(requestRepeatKey, nowUrlParams, time); } else { // 当前key存在 判断值是否一致 if (msg.equals(nowUrlParams)) { log.info("重复提交校验修改存在" msg); throw new BusinessException("112", "请勿重复提交或操作过于频繁"); } } } return null; }
3. 使用方式 , 在需要防重检查的情况下,加上关键
@ApiOperation(value = "新增", notes = "新增") @PostMapping("/add") @RepeatRequest(opened = true,time = 10) public void addTest(@RequestBody TestEntity entity) { testService.addTest(entity); }
4. 测试- 使用的swagger
第一次请求成功
10s内再次请求
