1.创建注解
/**
* 请求次数限制
* @author LXC
* @date 2023/2/16 20:31
*/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestFrequencyLimit {
//次数 默认50次
int limitNum() default 50;
//在time内调用的次数count -单位毫秒 默认1s
long frameTime() default 1000;
//锁定时间 -单位毫秒
long lockTime() default 1000*60*3;
//
RequestFrequencyConditionEnum condition() default RequestFrequencyConditionEnum.BY_IP_ADDRESS;
}
2.创建枚举
/**
* 接口限制条件
* @author LXC
* @date 2023/2/19 23:46
*/
@AllArgsConstructor
@Getter
public enum RequestFrequencyConditionEnum {
//根据用户编码
BY_USER_CODE(0, SecurityUtils.getLoginVo().getUserCode()),
//根据IP地址
BY_IP_ADDRESS(1, SecurityUtils.getIpAddress()),
;
private final Integer code;
private final String name;
}
3.创建常量
//请求次数限制
public final static String REQUEST_FREQUENCY_LIMIT = "requestFrequencyLimit:Limit:";
//请求次数限超出,锁住
public final static String REQUEST_FREQUENCY_LOCK = "requestFrequencyLimit:Lock:";
4.aop拦截
@Aspect
@Component
public class RequestFrequencyLimitAspect {
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Around("@annotation(com.server.common.security.code.anntation.RequestFrequencyLimit)")
public Object around(ProceedingJoinPoint point) throws Throwable {
Signature signature = point.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
RequestFrequencyLimit requestFrequencyLimit = method.getAnnotation(RequestFrequencyLimit.class);
String requestMappingValue = method.getDeclaringClass().getAnnotation(RequestMapping.class).path()[0]
+ ":" + method.getName()
;
String key = requestMappingValue + ":" + requestFrequencyLimit.condition().getName();
String limitKey = RedisKeysConstant.REQUEST_FREQUENCY_LIMIT + key;
String lockKey = RedisKeysConstant.REQUEST_FREQUENCY_LOCK + key;
Boolean lockHasKey = redisTemplate.hasKey(lockKey);
Boolean limitHasKey = redisTemplate.hasKey(limitKey);
//判断是否被锁定
if(Boolean.TRUE.equals(lockHasKey)){
throw new BusinessException("请求次数频繁,稍后再试");
}
Integer limitNum = (Integer) redisTemplate.opsForValue().get(limitKey);
int num = OptionalUtils.ofEmpty(limitNum).orElse(0) + 1;
//次数频繁
if(num > requestFrequencyLimit.limitNum()){
redisTemplate.opsForValue().set(lockKey,1,requestFrequencyLimit.lockTime(), TimeUnit.MILLISECONDS);
throw new BusinessException("请求次数频繁,稍后再试");
}
//如果存在- 计数+1
if(Boolean.TRUE.equals(limitHasKey)){
redisTemplate.opsForValue().increment(limitKey);
}
//不存在添加
if(Boolean.FALSE.equals(limitHasKey)){
redisTemplate.opsForValue().set(limitKey,1,requestFrequencyLimit.frameTime(), TimeUnit.MILLISECONDS);
}
return point.proceed();
}
}
5.使用
/**
* 登录
* @author LXC
* @date 2022/4/27 22:31
*/
@PostMapping(value = "/api/login")
@ApiOperation(value = "登录")
@RequestFrequencyLimit(limitNum = 2,frameTime = 1000,lockTime = 1000,condition = RequestFrequencyConditionEnum.BY_USER_CODE)
public AjaxResult login(@RequestBody @Validated LoginDto loginDto) {
LoginBo loginBo = BeanUtils.copyProperties(loginDto, LoginBo.class);
TokenVo tokenVo = authService.login(loginBo);
return AjaxResult.success(tokenVo,"登录成功");
}
5.欢迎加入QQ群 619474143,一起学习,一起进步