文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Springboot使用redis实现接口Api限流的方法

2023-06-20 18:03

关注

这篇文章主要介绍“Springboot使用redis实现接口Api限流的方法”,在日常操作中,相信很多人在Springboot使用redis实现接口Api限流的方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Springboot使用redis实现接口Api限流的方法”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

前言

该篇介绍的内容如题,就是利用redis实现接口的限流(  某时间范围内 最大的访问次数 ) 。

正文 

惯例,先看下我们的实战目录结构:

Springboot使用redis实现接口Api限流的方法

首先是pom.xml 核心依赖:

<!--用于redis数据库连接-->        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-data-redis</artifactId>        </dependency>        <!--用于redis lettuce 连接池pool使用-->        <dependency>            <groupId>org.apache.commons</groupId>            <artifactId>commons-pool2</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>

然后是application.yml里面的redis接入配置:

spring:  redis:    lettuce:      pool:        #连接池最大连接数 使用负值代表无限制 默认为8        max-active: 10        #最大空闲连接 默认8        max-idle: 10        #最小空闲连接 默认0        min-idle: 1    host: 127.0.0.1    password: 123456    port: 6379    database: 0    timeout: 2000msserver:  port: 8710

redis的配置类, RedisConfig.java:

ps:可以看到日期是18年的,因为这些redis的整合教程,在这个系列里面一共有快10篇,不了解的看客如果感兴趣可以去看一看。

import com.fasterxml.jackson.annotation.JsonAutoDetect;import com.fasterxml.jackson.annotation.PropertyAccessor;import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.cache.CacheManager;import org.springframework.cache.annotation.EnableCaching;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.cache.RedisCacheConfiguration;import org.springframework.data.redis.cache.RedisCacheManager;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;import org.springframework.data.redis.serializer.RedisSerializationContext;import org.springframework.data.redis.serializer.StringRedisSerializer; import static org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig; @Configuration@EnableCachingpublic class RedisConfig {    @Bean    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {        RedisCacheConfiguration cacheConfiguration =                defaultCacheConfig()                        .disableCachingNullValues()                        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new Jackson2JsonRedisSerializer(Object.class)));        return RedisCacheManager.builder(connectionFactory).cacheDefaults(cacheConfiguration).build();    }      @Bean    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();        redisTemplate.setConnectionFactory(factory);        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);        ObjectMapper om = new ObjectMapper();        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);        jackson2JsonRedisSerializer.setObjectMapper(om);        //序列化设置 ,这样为了存储操作对象时正常显示的数据,也能正常存储和获取        redisTemplate.setKeySerializer(new StringRedisSerializer());        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);        redisTemplate.setHashKeySerializer(new StringRedisSerializer());        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);        return redisTemplate;    }    @Bean    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();        stringRedisTemplate.setConnectionFactory(factory);        return stringRedisTemplate;    }}

自定义注解:

import java.lang.annotation.*; @Inherited@Documented@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface RequestLimit {         int second() default 10;          int maxCount() default 5;      //默认效果 : 10秒内 对于使用该注解的接口,只能总请求访问数 不能大于 5次 }

接下来是拦截器 RequestLimitInterceptor.java:

拦截接口的方式 是通过 ip地址+接口url ,做时间内的访问计数

import com.elegant.testdemo.annotation.RequestLimit;import com.elegant.testdemo.utils.IpUtil;import com.fasterxml.jackson.databind.ObjectMapper;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.stereotype.Component;import org.springframework.web.method.HandlerMethod;import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.concurrent.TimeUnit;  @Componentpublic class RequestLimitInterceptor implements HandlerInterceptor {    private final Logger log = LoggerFactory.getLogger(this.getClass());     @Autowired    private RedisTemplate<String, Object> redisTemplate;     @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        try {            if (handler instanceof HandlerMethod) {                HandlerMethod handlerMethod = (HandlerMethod) handler;                // 获取RequestLimit注解                RequestLimit requestLimit = handlerMethod.getMethodAnnotation(RequestLimit.class);                if (null==requestLimit) {                    return true;                }                //限制的时间范围                int seconds = requestLimit.second();                //时间内的 最大次数                int maxCount = requestLimit.maxCount();                String ipAddr = IpUtil.getIpAddr(request);                // 存储key                String key =  ipAddr+":"+request.getContextPath() + ":" + request.getServletPath();                // 已经访问的次数                Integer count = (Integer) redisTemplate.opsForValue().get(key);                log.info("检测到目前ip对接口={}已经访问的次数", request.getServletPath() , count);                if (null == count || -1 == count) {                    redisTemplate.opsForValue().set(key, 1, seconds, TimeUnit.SECONDS);                    return true;                }                if (count < maxCount) {                    redisTemplate.opsForValue().increment(key);                    return true;                }                log.warn("请求过于频繁请稍后再试");                returnData(response);                return false;            }            return true;        } catch (Exception e) {            log.warn("请求过于频繁请稍后再试");            e.printStackTrace();        }        return true;    }     public void returnData(HttpServletResponse response) throws IOException {        response.setCharacterEncoding("UTF-8");        response.setContentType("application/json; charset=utf-8");        ObjectMapper objectMapper = new ObjectMapper();        //这里传提示语可以改成自己项目的返回数据封装的类        response.getWriter().println(objectMapper.writeValueAsString("请求过于频繁请稍后再试"));        return;    } }

接下来是 拦截器的配置 WebConfig.java:

 import com.elegant.testdemo.interceptor.RequestLimitInterceptor;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;  @Configurationpublic class WebConfig implements WebMvcConfigurer {    @Autowired    private RequestLimitInterceptor requestLimitInterceptor;     @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(requestLimitInterceptor)                 //拦截所有请求路径                .addPathPatterns("@RestControllerpublic class TestController {     @GetMapping("/test")    @RequestLimit(maxCount = 3,second = 60)    public String test() {        return "你好,如果对你有帮助,请点赞加关注。";    } }

这个/test接口的注解,我们设置的是 60秒内 最大访问次数为 3次 (实际应用应该是根据具体接口做相关的次数限制。)

然后使用postman测试一下接口:

前面三次都是请求通过的:

Springboot使用redis实现接口Api限流的方法 

Springboot使用redis实现接口Api限流的方法

 第四次:

Springboot使用redis实现接口Api限流的方法

到此,关于“Springboot使用redis实现接口Api限流的方法”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯