104 lines
3.6 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.example.utils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
/**
* 限流通用工具
* 针对于不同的情况进行限流操作,支持限流升级
*/
@Slf4j
@Component
public class FlowUtils {
@Resource
StringRedisTemplate template;
private static final LimitAction defaultAction = overclock -> overclock;
/**
* 针对于单次频率限制请求成功后在冷却时间内不得再次进行请求如3秒内不能再次发起请求
* @param key 键
* @param blockTime 限制时间
* @return 是否通过限流检查
*/
public boolean limitOnceCheck(String key, int blockTime){
return this.internalCheck(key, 1, blockTime, defaultAction);
}
/**
* 针对于单次频率限制,请求成功后,在冷却时间内不得再次进行请求
* 如3秒内不能再次发起请求如果不听劝阻继续发起请求将限制更长时间
* @param key 键
* @param frequency 请求频率
* @param baseTime 基础限制时间
* @param upgradeTime 升级限制时间
* @return 是否通过限流检查
*/
public boolean limitOnceUpgradeCheck(String key, int frequency, int baseTime, int upgradeTime){
return this.internalCheck(key, frequency, baseTime, (overclock) -> {
if (overclock)
template.opsForValue().set(key, "1", upgradeTime, TimeUnit.SECONDS);
return false;
});
}
/**
* 针对于在时间段内多次请求限制如3秒内限制请求20次超出频率则封禁一段时间
* @param counterKey 计数键
* @param blockKey 封禁键
* @param blockTime 封禁时间
* @param frequency 请求频率
* @param period 计数周期
* @return 是否通过限流检查
*/
public boolean limitPeriodCheck(String counterKey, String blockKey, int blockTime, int frequency, int period){
return this.internalCheck(counterKey, frequency, period, (overclock) -> {
if (overclock)
template.opsForValue().set(blockKey, "", blockTime, TimeUnit.SECONDS);
return !overclock;
});
}
/**
* 限制某一段时间内的请求次数如3秒内限制请求20次
* @param counterKey 计数键
* @param frequency 请求频率
* @param period 计数周期
* @return 是否通过限流检查
*/
public boolean limitPeriodCounterCheck(String counterKey, int frequency, int period){
return this.internalCheck(counterKey, frequency, period, defaultAction);
}
/**
* 内部使用请求限制主要逻辑
* @param key 计数键
* @param frequency 请求频率
* @param period 计数周期
* @param action 限制行为与策略
* @return 是否通过限流检查
*/
private boolean internalCheck(String key, int frequency, int period, LimitAction action){
if (Boolean.TRUE.equals(template.hasKey(key))) {
Long value = Optional.ofNullable(template.opsForValue().increment(key)).orElse(0L);
return action.run(value > frequency);
} else {
template.opsForValue().set(key, "1", period, TimeUnit.SECONDS);
return true;
}
}
/**
* 内部使用,限制行为与策略
*/
private interface LimitAction {
boolean run(boolean overclock);
}
}