接口实现限流

基本流程

定义注解

定义切面类,切点是指定的注解

使用注解修饰限流的控制层接口

 

package com.renr.hisapp.common.anno;

import java.lang.annotation.*;

/**
 * 用户访问接口时的限流注解
 */
// @Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface VisitRateLimit {
    /**
     * 限流时长,单位秒
     */
    int time() default 60;

    /**
     * 限流次数
     */
    int count() default 100;

    /**
     * 限流后返回的信息
     */
    String msg() default "访问过于频繁,请稍候再试";

}

 

package com.renr.hisapp.common.aop;

import com.renr.common.JsonResult;
import com.renr.exception.CustomerException;
import com.renr.hisapp.common.anno.VisitRateLimit;
import com.renr.utils.RedisUtils;
import com.renr.utils.TokenUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Component
@Aspect
public class VisitRateLimitAspect {

    public VisitRateLimitAspect() {
        System.out.println("ccc");
    }

    @Pointcut("@annotation(com.renr.hisapp.common.anno.VisitRateLimit)")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void before() {
        System.out.println("before");
    }

    @Around("pointcut()")
    public Object doBefore(ProceedingJoinPoint joinPoint) {
        // 获取注解的方法参数列表
        Object[] args = joinPoint.getArgs();

        // 获取请求对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        Long userId = TokenUtils.getUserId(request);
        String key = "sk:limit:" + userId;

        // 获取被注解的方法
        MethodInvocationProceedingJoinPoint mjp = (MethodInvocationProceedingJoinPoint) joinPoint;
        MethodSignature signature = (MethodSignature) mjp.getSignature();
        Method method = signature.getMethod();
        String[] parameterNames = signature.getParameterNames();

        // 获取方法上的注解
        try {
            VisitRateLimit rateLimit = method.getAnnotation(VisitRateLimit.class);
            if (rateLimit == null) {
                // 如果没有注解
                return JsonResult.error("限流注解不存在");
            }
            int time = rateLimit.time();
            int count = rateLimit.count();
            // 判断key是否存在,不存在创建,存在判断是否超过限制
            if (RedisUtils.hasKey(key)) {
                Long incrKey = RedisUtils.incrKey(key);
                if (incrKey > count) {
                    return JsonResult.error(rateLimit.msg());
                }
            } else {
                RedisUtils.setValueTimeout(key, 1, time);
            }
            // 执行目标方法
            return joinPoint.proceed();
        } catch (Throwable e) {
            throw new CustomerException(e.getMessage());
        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值