SpringBoot实现一个Redis限流注解

springBoot实现的一个限流注解

文章目录

目录

文章目录

一、使用步骤

1.引入库

2.代码实现

1.添加注解

2.新增限流AOP实现

3.实现代码的拦截

4.最终结果

总结

一、使用步骤

1.引入库

代码如下(示例):

XML 复制代码
        <!-- 引入SpringBoot Aop依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2.代码实现

1.添加注解

java 复制代码
package com.hhh.springai_test.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisLimiting {

    int number() default 3;

    int time() default 60;

    String message() default "请求过于频繁,请稍后再试";


}

2.新增限流AOP实现

java 复制代码
package com.hhh.springai_test.aop;

import cn.hutool.crypto.digest.MD5;
import com.hhh.springai_test.annotation.RedisLimiting;
import com.hhh.springai_test.common.ErrorCode;
import com.hhh.springai_test.exception.BusinessException;
import com.hhh.springai_test.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

@Aspect
@Component("redisLimitingAspect")
@Slf4j
public class RedisLimitingAspect {

    @Autowired
    private RedisUtils redisUtils;

    @Around("@annotation(com.hhh.springai_test.annotation.RedisLimiting)")  // 只拦截带 @redisLimiting 的方法
    public Object redisLimiting(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod(); // 直接获取被代理的方法
        // 获取 @redisLimiting 注解
        RedisLimiting annotation = method.getAnnotation(RedisLimiting.class);
        if (annotation == null) {
            return joinPoint.proceed(); // 没有注解,直接执行方法
        }
        int limit = annotation.number(); // 限制次数
        int expire = annotation.time();  // 过期时间
        String message = annotation.message();

        log.info("拦截方法: {}, 限流 key: {}, 限流次数: {}, 过期时间: {} 秒",
                method.getName(), limit, expire);

        // 执行限流逻辑
        boolean isAllowed = checkRedisLimiting(method, joinPoint.getArgs(), limit, expire);
        if (!isAllowed) {
            throw new BusinessException(ErrorCode.BUSY_ERROR,message);
        }

        return joinPoint.proceed(); // 执行原方法
    }

    private boolean checkRedisLimiting(Method method, Object[] args, int limit, int expire) {
        // 生成 Redis Key
        String redisKey = generateRedisKey(method, args);
        // 查询 Redis 是否存在
        Object o = redisUtils.get(redisKey);
        if (o == null) {
            redisUtils.setex(redisKey, 1, expire); // 初始值设为1,并设置过期时间
            return true;
        } else {
            int count = Integer.parseInt(o.toString());
            if (count >= limit) {
                return false; // 超过限制
            } else {
                redisUtils.increment(redisKey, 1); // 递增计数
                return true;
            }
        }
    }

    private String generateRedisKey(Method method, Object[] args) {
        StringBuilder builder = new StringBuilder();
        builder.append(method.getDeclaringClass().getName()).append(":").append(method.getName()).append(":");
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            builder.append(parameters[i].getName()).append("=").append(args[i]).append("&");
        }
        return MD5.create().digestHex16(builder.toString()); // 生成唯一 Redis Key
    }
}

3.实现代码的拦截

java 复制代码
@GetMapping("/getAllModel")
    @RedisLimiting(number = 3, time = 60,message = "不要再请求我的获取aiModel方法了")
    public BaseResponse<List<AiModelVO>> getAllModel() {
        return ResultUtils.success(aiModelService.getAllModel());
    }

4.最终结果


总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

相关推荐
尚学教辅学习资料9 分钟前
Ruoyi-vue-plus-5.x第五篇Spring框架核心技术:5.1 Spring Boot自动配置
vue.js·spring boot·spring
Arva .9 分钟前
Redis
数据库·redis·缓存
博一波26 分钟前
Redis 集群:连锁银行的 “多网点智能协作系统”
数据库·redis·缓存
晚安里28 分钟前
Spring 框架(IoC、AOP、Spring Boot) 的必会知识点汇总
java·spring boot·spring
秋难降32 分钟前
SQL 索引突然 “罢工”?快来看看为什么
数据库·后端·sql
上官浩仁1 小时前
springboot ioc 控制反转入门与实战
java·spring boot·spring
Access开发易登软件1 小时前
Access开发导出PDF的N种姿势,你get了吗?
后端·低代码·pdf·excel·vba·access·access开发
叫我阿柒啊2 小时前
从Java全栈到前端框架:一位程序员的实战之路
java·spring boot·微服务·消息队列·vue3·前端开发·后端开发
中国胖子风清扬2 小时前
Rust 序列化技术全解析:从基础到实战
开发语言·c++·spring boot·vscode·后端·中间件·rust
bobz9653 小时前
分析 docker.service 和 docker.socket 这两个服务各自的作用
后端