返回介绍

69.自定义注解限制重复提交

发布于 2020-09-14 22:20:47 字数 5613 浏览 1145 评论 0 收藏 0

@author ksf 处理的方式有两种,本次介绍普适性方案,解决问题1。

1.正常业务请求的防止限制

2.极端情况下的请求,rediskey过期带来的重复请求。

代码结构比较清晰,直接贴代码啦:


@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface LimitSubmit {
    String key() ;
    /**
     * 默认 10s
     */
    int limit() default 10;

    /**
     * 请求完成后 是否一直等待
     * true则等待
     * @return
     */
    boolean needAllWait() default true;
}

Component
@Aspect
@Slf4j
public class LimitSubmitAspect {
    //封装了redis操作各种方法
    @Autowired
    private RedisUtil redisUtil;
    @Pointcut("@annotation(org.jeecg.common.aspect.annotation.LimitSubmit)")
    private void pointcut() {}

    @Around("pointcut()")
    public Object handleSubmit(ProceedingJoinPoint joinPoint) throws Throwable {
        LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        //获取注解信息
        LimitSubmit limitSubmit = method.getAnnotation(LimitSubmit.class);
        int submitTimeLimiter = limitSubmit.limit();
        String redisKey = limitSubmit.key();
        boolean needAllWait = limitSubmit.needAllWait();
        String key =  getRedisKey(sysUser,joinPoint, redisKey);
        Object result = redisUtil.get(key);
        if (result != null) {
            throw new JeecgBootException("请勿重复访问!");
        }
        redisUtil.set(  key,  sysUser.getId(),submitTimeLimiter);
        try {
            Object proceed = joinPoint.proceed();
            return proceed;
        } catch (Throwable e) {
            log.error("Exception in {}.{}() with cause = \'{}\' and exception = \'{}\'", joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName(), e.getCause() != null? e.getCause() : "NULL", e.getMessage(), e);
            throw e;
        }finally {
            if(!needAllWait) {
                redisUtil.del(redisKey);
            }
        }
    }

    /**
     * 支持多参数,从请求参数进行处理
     */
    private String   getRedisKey(LoginUser sysUser,ProceedingJoinPoint joinPoint ,String key ){
        if(key.contains("%s")) {
            key = String.format(key, sysUser.getId());
        }
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();

        LocalVariableTableParameterNameDiscoverer  discoverer = new LocalVariableTableParameterNameDiscoverer();
        String[] parameterNames = discoverer.getParameterNames(method);
        if (parameterNames != null) {
            for (int i=0; i < parameterNames.length; i++  ) {
                String item = parameterNames[i];
                if(key.contains("#"+item)){
                    key = key.replace("#"+item, joinPoint.getArgs()[i].toString());
                }
            }
        }
        return key.toString();
    }
}

使用效果: 在这里插入图片描述

使用: 
 @LimitSubmit(key = "testLimit:%s:#orderId",limit = 10,needAllWait = true)
    %S 代表当前登录人
    #参数 代表从参数中获取,支持多个参数
生成的redis key: testLimit:e9ca23d68d884d4ebb19d07889727dae:order1123123

1.限制对某个接口的访问,针对所有人 ,则去除%S 2.限制某个人对某个接口的访问,则 %S 3.限制某个人对某个接口的业务参数的访问,则 %S:#参数1:#参数2 在这里插入图片描述 在这里插入图片描述

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文