注解
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE,METHOD})
public @interface AccessLimit {
long second() default 5L;
long maxTime() default 3L;
long forbiddenTime() default 120L;
}
Controller
@RestController
@AccessLimit(second = 3,maxTime = 2,forbiddenTime = 40L)
public class HelloController {
@AccessLimit(second = 10,maxTime = 2,forbiddenTime = 40L)
@GetMapping("/hello")
public String hello(){
return "hello";
}
}
AccessLimitInterceptor拦截器
@Slf4j
public class AccessLimitInterceptor implements HandlerInterceptor {
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Value("${interfaceAccess.second}")
private Long second = 10L;
@Value("${interfaceAccess.time}")
private Long time = 3L;
@Value("${interfaceAccess.lockTime}")
private Long lockTime = 60L;
public static final String LOCK_PREFIX = "LOCK";
public static final String COUNT_PREFIX = "COUNT";
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod targetMethod = (HandlerMethod) handler;
AccessLimit targetClassAnnotation = targetMethod.getMethod().getDeclaringClass().getAnnotation(AccessLimit.class);
boolean isBrushForAllInterface = false;
String ip = request.getRemoteAddr();
String uri = request.getRequestURI();
long second = 0L;
long maxTime = 0L;
long forbiddenTime = 0L;
if (!Objects.isNull(targetClassAnnotation)) {
log.info("目标接口方法所在类上有@AccessLimit注解");
isBrushForAllInterface = true;
second = targetClassAnnotation.second();
maxTime = targetClassAnnotation.maxTime();
forbiddenTime = targetClassAnnotation.forbiddenTime();
}
AccessLimit accessLimit = targetMethod.getMethodAnnotation(AccessLimit.class);
if (!Objects.isNull(accessLimit)) {
second = accessLimit.second();
maxTime = accessLimit.maxTime();
forbiddenTime = accessLimit.forbiddenTime();
if (isForbindden(second, maxTime, forbiddenTime, ip, uri)) {
throw new BusinessException(RespCodeEnum.ACCESS_FREQUENT);
}
} else {
if (isBrushForAllInterface && isForbindden(second, maxTime, forbiddenTime, ip, uri)) {
throw new BusinessException(RespCodeEnum.ACCESS_FREQUENT);
}
}
}
return true;
}
private boolean isForbindden(long second, long maxTime, long forbiddenTime, String ip, String uri) {
String lockKey = LOCK_PREFIX + ip + uri;
Object isLock = redisTemplate.opsForValue().get(lockKey);
if (Objects.isNull(isLock)) {
String countKey = COUNT_PREFIX + ip + uri;
Object count = redisTemplate.opsForValue().get(countKey);
if (Objects.isNull(count)) {
log.info("首次访问");
redisTemplate.opsForValue().set(countKey, 1, second, TimeUnit.SECONDS);
} else {
if ((Integer) count < maxTime) {
redisTemplate.opsForValue().increment(countKey);
} else {
log.info("{}禁用访问{}", ip, uri);
redisTemplate.opsForValue().set(lockKey, 1, forbiddenTime, TimeUnit.SECONDS);
redisTemplate.delete(countKey);
return true;
}
}
} else {
return true;
}
return false;
}
}
WebConfig
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public AccessLimitInterceptor creatAccessLimitInterceptor() {
return new AccessLimitInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(creatAccessLimitInterceptor())
.addPathPatterns("/**");
}
}