SpringBoot + Redis 实现接口访问次数

1.创建注解


/**
 * 请求次数限制
 * @author LXC
 * @date 2023/2/16 20:31
 */
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestFrequencyLimit {

    //次数  默认50次
    int limitNum() default 50;

    //在time内调用的次数count -单位毫秒 默认1s
    long frameTime() default 1000;

    //锁定时间 -单位毫秒
    long lockTime() default 1000*60*3;

    //
    RequestFrequencyConditionEnum condition() default RequestFrequencyConditionEnum.BY_IP_ADDRESS;
}

2.创建枚举

/**
 * 接口限制条件
 * @author LXC
 * @date 2023/2/19 23:46
 */
@AllArgsConstructor
@Getter
public enum RequestFrequencyConditionEnum {
    //根据用户编码
    BY_USER_CODE(0, SecurityUtils.getLoginVo().getUserCode()),
    //根据IP地址
    BY_IP_ADDRESS(1, SecurityUtils.getIpAddress()),

    ;

    private final Integer code;

    private final String name;
}

3.创建常量

    //请求次数限制
    public final static String REQUEST_FREQUENCY_LIMIT =  "requestFrequencyLimit:Limit:";
    //请求次数限超出,锁住
    public final static String REQUEST_FREQUENCY_LOCK =  "requestFrequencyLimit:Lock:";

4.aop拦截

@Aspect
@Component
public class RequestFrequencyLimitAspect {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Around("@annotation(com.server.common.security.code.anntation.RequestFrequencyLimit)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        RequestFrequencyLimit requestFrequencyLimit = method.getAnnotation(RequestFrequencyLimit.class);

        String requestMappingValue = method.getDeclaringClass().getAnnotation(RequestMapping.class).path()[0]
                                     + ":" + method.getName()
                ;

        String key = requestMappingValue + ":" + requestFrequencyLimit.condition().getName();

        String limitKey = RedisKeysConstant.REQUEST_FREQUENCY_LIMIT + key;
        String lockKey = RedisKeysConstant.REQUEST_FREQUENCY_LOCK + key;

        Boolean lockHasKey = redisTemplate.hasKey(lockKey);
        Boolean limitHasKey = redisTemplate.hasKey(limitKey);

        //判断是否被锁定
        if(Boolean.TRUE.equals(lockHasKey)){
            throw new BusinessException("请求次数频繁,稍后再试");
        }

        Integer limitNum = (Integer) redisTemplate.opsForValue().get(limitKey);
        int num = OptionalUtils.ofEmpty(limitNum).orElse(0) + 1;

        //次数频繁
        if(num > requestFrequencyLimit.limitNum()){
            redisTemplate.opsForValue().set(lockKey,1,requestFrequencyLimit.lockTime(), TimeUnit.MILLISECONDS);
            throw new BusinessException("请求次数频繁,稍后再试");
        }

        //如果存在- 计数+1
        if(Boolean.TRUE.equals(limitHasKey)){
            redisTemplate.opsForValue().increment(limitKey);
        }
        //不存在添加
        if(Boolean.FALSE.equals(limitHasKey)){
            redisTemplate.opsForValue().set(limitKey,1,requestFrequencyLimit.frameTime(), TimeUnit.MILLISECONDS);
        }

        return point.proceed();
    }

}

5.使用

    /**
     * 登录
     * @author LXC
     * @date 2022/4/27 22:31
     */
    @PostMapping(value = "/api/login")
    @ApiOperation(value = "登录")
    @RequestFrequencyLimit(limitNum = 2,frameTime = 1000,lockTime = 1000,condition = RequestFrequencyConditionEnum.BY_USER_CODE)
    public AjaxResult login(@RequestBody @Validated LoginDto loginDto) {
        LoginBo loginBo = BeanUtils.copyProperties(loginDto, LoginBo.class);
        TokenVo tokenVo = authService.login(loginBo);
        return AjaxResult.success(tokenVo,"登录成功");
    }

5.欢迎加入QQ群 619474143,一起学习,一起进步

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值