基本流程
定义注解
定义切面类,切点是指定的注解
使用注解修饰限流的控制层接口
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());
}
}
}