添加自定义AccessLimit注解,使用注解方式实现接口的限流操作
import java.lang.annotation.*;
/**
* 接口防刷限流
* <p>
* 限流是通过拦截器实现
*
* @author H.Yang
* @date 2022/12/14
*/
@Documented
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessLimit {
/**
* 指定second 时间内 API请求次数
*/
int maxCount() default 5;
/**
* 请求次数的指定时间范围 秒数(redis数据过期时间)
*/
int second() default 60;
}
编写拦截器
import cn.hutool.core.convert.Convert;
import com.xh.jedis.annotation.AccessLimit;
import com.xh.jedis.repository.JedisRepository;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
/**
* API 接口防刷限流
*
* @author H.Yang
* @date 2022/12/14
*/
@Slf4j
@AllArgsConstructor
public class AccessLimitInterceptor implements HandlerInterceptor {
private final JedisRepository jedisRepository;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// Handler 是否为 HandlerMethod 实例
if (handler instanceof HandlerMethod) {
// 强转
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 获取方法
Method method = handlerMethod.getMethod();
// 是否有AccessLimit注解
if (!method.isAnnotationPresent(AccessLimit.class)) {
return true;
}
// 获取注解内容信息
AccessLimit accessLimit = method.getAnnotation(AccessLimit.class);
if (accessLimit == null) {
return true;
}
// 存储key
String key = request.getRemoteAddr() + ":" + request.getContextPath() + ":" + request.getServletPath();
// 已经访问的次数
Integer count = Convert.toInt(jedisRepository.get(key), 0);
System.out.println("已经访问的次数:" + count);
if (count < 1) {
jedisRepository.setex(key, "1", accessLimit.second());
return true;
}
if (count < accessLimit.maxCount()) {
jedisRepository.incr(key);
return true;
}
if (count >= accessLimit.maxCount()) {
log.warn("请求过于频繁请稍后再试");
return false;
}
}
return true;
}
}
使用 AccessLimit
@Slf4j
@RestController
@RequestMapping("access")
public class AccessLimitController {
/**
* 限流测试
*/
@GetMapping
@AccessLimit(maxCount = 5,second = 60)
public String limit(HttpServletRequest request) {
log.info("Access Limit Test");
return "限流测试";
}
}