欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring boot使用redis限制接口访问次数

程序员文章站 2022-03-19 16:01:41
spring boot使用redis限制接口访问次数...

首先自定义一个注解用于需要限制访问次数的接口

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestLimit {

    //限制访问次数
    int limitCount() default 3;
    
    //超时时间
    long expireTime() default 60L;

    //请求url
    String requestUrl() default "";

}

切面用于执行具体的操作

@Component
@Aspect
public class RequestLimitAspect {

    @Autowired
    private RedisUtils redisUtils;

    @Pointcut("@annotation(requestLimit)")
    public void limit(RequestLimit requestLimit) {

    }

    @Around("limit(requestLimit)")
    public Object requestLimitLog(ProceedingJoinPoint joinPoint, RequestLimit requestLimit) throws Throwable {
        HttpServletRequest request = null;
        HttpServletResponse response = null;
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            if(arg instanceof HttpServletRequest)
                request = (HttpServletRequest) arg;
            if(arg instanceof HttpServletResponse)
                response = (HttpServletResponse) arg;
        }
        if (request == null || response == null)
            return null;
        String sessionId = request.getSession().getId();
        String key = sessionId + requestLimit.requestUrl();
        long limitTime = requestLimit.expireTime();
        //从redis获取值
        Object requestCount = redisUtils.get(key);
        //首次访问初始化请求次数及过期时间,后续访问时判断请求次数是否超过限制次数
        if (requestCount == null) {
            redisUtils.set(key, 1, limitTime);
        } else if(Integer.valueOf(requestCount.toString()) >= requestLimit.limitCount()) {
            //超过限制次数返回对应枚举值
            LoginHandlerInterceptor.handlerErrorResponse(response, RetEnum.REQUEST_LIMITED);
            return null;
        } else {
            //更新访问次数及过期时间
            Integer count = Integer.valueOf(requestCount.toString()) + 1;
            redisUtils.set(key, count, limitTime);
        }
        return joinPoint.proceed(args);
    }

}

handlerErrorResponse方法用于返回错误信息

public static void handlerErrorResponse(HttpServletResponse response, RetEnum retEnum) throws Exception {
        response.setStatus(200);
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        try (PrintWriter writer = response.getWriter()) {
            String result = "{\"state\": \""
                    .concat(retEnum.getCode().toString())
                    .concat("\",\"msg\": \"")
                    .concat(retEnum.getMsg())
                    .concat("\"}");
            writer.write(result);
            writer.flush();
        } catch (Exception e) {
            throw new Exception("系统异常!");
        }
    }

RetEnum枚举

public enum RetEnum {
    /**
     * 请求被限制
     */
    REQUEST_LIMITED (1004,"请求被限制!"),
    private Integer code;
    private String msg;

    RetEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

Controller

@RestController
public class HelloController {

    @RequestLimit(requestUrl = "/hello")
    @RequestMapping("/hello")
    public String hello(@RequestParam String name, HttpServletRequest request, HttpServletResponse response) {
        return "Hello " + name;
    }
}

第1,2,3次执行结果

Hello test

第4次执行结果

{
    "state": "1004",
    "msg": "请求禁止!"
}

本文地址:https://blog.csdn.net/zt980995264/article/details/112009051