AOP实现接口重复提交校验

概要

利用注解在那些需要需要重复校验的接口上
在aop切面中拦截参数,
把 签名sign = MD5(参数+requestURI+userId),存储在redis中,存储5秒钟,以后的每次请求都要判断redis中是否存在重复sign

具体实现

/**
 * 防止重复提交标记注解
 *
 * @author sairobo
 * @date 2019年11月26日 上午10:19:56
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NoRepeatSubmit {
    /**
     * 几秒之内无法重复提交请求(单位秒)
     *
     * @return
     */
    int expire() default 5;
}

@Aspect
@Configuration
@Slf4j
public class NoRepeatSubmitAspect {

    @Autowired
    private RedisUtils redisUtils;

    @NacosValue("${api.norepeat.submit.open:true}")
    private boolean isOpen;

    @Pointcut("@annotation(edu.xxx.web.modules.openapi.annotation.NoRepeatSubmit)")
    public void noRepeatSubmit() {

    }

    @Around("noRepeatSubmit()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        if (!isOpen) {
            return pjp.proceed();
        }

        Stopwatch watch = Stopwatch.createStarted();
        Object proceed;
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        NoRepeatSubmit noRepeatSubmit = method.getAnnotation(NoRepeatSubmit.class);

        // 执行验证
        executeValidation(HttpKit.getRequest(), pjp, noRepeatSubmit.expire());
        log.error(" 校验执行时长:{} {}!", watch.elapsed(TimeUnit.MILLISECONDS), "毫秒");

        proceed = pjp.proceed();
        return proceed;

    }

    /**
     * 验证是否重复提交
     * @param request
     * @param pjp
     * @param expire 超时,单位秒
     * @throws IOException
     */
    private void executeValidation(HttpServletRequest request, ProceedingJoinPoint pjp, int expire) throws IOException {
        String requestURI = request.getRequestURI();
        Object[] args = pjp.getArgs();
        String paramJsonStr = "";
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                paramJsonStr.concat(JSON.toJSONString(args[i]));
            }
        }
        Long swUserId = Convert.toLong(request.getAttribute(USER_KEY));

        // sign = md5(请求参数的json请求体字符串 + requestURI + swUserId)
        String digest = DigestUtils.md5DigestAsHex((paramJsonStr.concat(requestURI).concat(Convert.toStr(swUserId, "")).getBytes()));

        if (redisUtils.exists(digest)) {
            throw new RRException("重复请求!", HttpStatus.INTERNAL_SERVER_ERROR.value());
        }

        redisUtils.set(digest, 1, expire);
    }


}

你可能感兴趣的:(AOP实现接口重复提交校验)