SpringBoot+Redis实现接口限流

1.redis接口限流注解

定义一个注解标明需要使用限流的接口

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AccessLimit {

    /**
     * @return 单位时间(秒)
     */
    int seconds();

    /**
     * @return 单位时间最大请求次数
     */
    int maxCount();
}

2.配置拦截器

在springboot的拦截器中,如果你没有配置拦截器,需要自定义类继承HandlerInterceptor,

@Log4j2
public class WebSecurityHandler implements HandlerInterceptor {
    @Autowired
    private RedisService redisService;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {
        //如果请求输入方法
        if (handler instanceof HandlerMethod) {
            HandlerMethod hm = (HandlerMethod) handler;
            //获取方法中的注解,看是否有该注解
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            if (accessLimit != null) {
                long seconds = accessLimit.seconds();
                int maxCount = accessLimit.maxCount();
                //关于key的生成规则可以自己定义 本项目需求是对每个方法都加上限流功能,如果你只是针对ip地址限流,那么key只需要只用ip就好
                String key = IpUtils.getIpAddress(httpServletRequest) + hm.getMethod().getName();
                //从redis中获取用户访问的次数
                try {
                    //此操作代表获取该key对应的值自增1后的结果
                    long q = redisService.incrExpire(key, seconds);
                    if (q > maxCount) {
                        render(httpServletResponse, Result.ok(null, "请求过于频繁,请稍候再试"));
                        log.warn(key + "请求次数超过每" + seconds + "秒" + maxCount + "次");
                        return false;
                    }
                    return true;
                } catch (RedisConnectionFailureException e) {
                    log.warn("redis错误: " + e.getMessage());
                    return true;
                }
            }
        }
        return false;
    }

    private void render(HttpServletResponse response, Result<?> result) throws Exception {
        response.setContentType("application/json;charset=UTF-8");
        OutputStream out = response.getOutputStream();
        String str = JSON.toJSONString(result);
        out.write(str.getBytes("UTF-8"));
        out.flush();
        out.close();
    }
}

3.测试注解

@AccessLimit(seconds = 10, maxCount = 2)

访问受限测试
在这里插入图片描述
redis信息
在这里插入图片描述
后台打印信息
在这里插入图片描述