⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/qq_34963282/article/details/89489009/ 「偷松果的松鼠」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

在这之前对redis一无所知,做的过程都是参考网上的资料,如果有冒犯之处请见谅,整理一下,希望对大家都用。

1.使用maven添加依赖库,本项目中使用的是:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>

2.配置redis服务

下载地址:

https://github.com/MicrosoftArchive/redis/releases

下载完成后启动即可

linux安装教程可参考:

https://blog.csdn.net/fm_vae/article/details/80234340

3.回到正题,目的是使用redis达到接口限流的效果。

定义一个注解标明需要使用限流的接口

@Retention(RUNTIME)
@Target(METHOD)
public @interface AccessLimit {

int seconds();
int maxCount();
}

在springboot的拦截器中,如果你没有配置拦截器,需要自定义类继承HandlerInterceptor

  @Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {
//如果请求输入方法
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
//获取方法中的注解,看是否有该注解
AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
if (accessLimit != null) {
long seconds = accessLimit.seconds();
int maxCount = accessLimit.maxCount();
//关于key的生成规则可以自己定义 本项目需求是对每个方法都加上限流功能,如果你只是针对ip地址限流,那么key只需要只用ip就好
String key = SystemUtil.getClientIp(httpServletRequest)+hm.getMethod().getName();

//从redis中获取用户访问的次数
try {
long q = redisService.incr(key, seconds);//此操作代表获取该key对应的值自增1后的结果
if (q > maxCount) {
//加1
render(httpServletResponse, new ResponseMsg(0, "请求过于频繁,请稍候再试", null)); //这里的CodeMsg是一个返回参数
return false;
}
return true;
}catch (RedisConnectionFailureException e){
logger.info("redis错误"+e.getMessage().toString());
return true;
}
}

}


return false;
}

private void render(HttpServletResponse response, ResponseMsg cm) throws Exception {
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
String str = new Gson().toJson(cm);
out.write(str.getBytes("UTF-8"));
out.flush();
out.close();
}

上面使用到的redisservice

public interface  RedisService {

/**
* set存数据
* @param key
* @param value
* @return
*/
boolean set(String key, String value);

/**
* get获取数据
* @param key
* @return
*/
String get(String key);

/**
* 设置有效天数
* @param key
* @param expire
* @return
*/
boolean expire(String key, long expire);

/**
* 移除数据
* @param key
* @return
*/
boolean remove(String key);

/**
* 获取自增1后的 值
* @param key
* @param time
* @return
*/
Long incr(String key,long time);
}

redisservice的实现类

@Service("redisService")
public class RedisServiceImpl implements RedisService {


@Resource
private RedisTemplate<String, ?> redisTemplate;


@Override
public boolean set(final String key, final String value) {
boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
connection.set(serializer.serialize(key), serializer.serialize(value));
return true;
}
});
return result;
}

@Override
public String get(final String key) {
String result = redisTemplate.execute(new RedisCallback<String>() {
@Override
public String doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
byte[] value = connection.get(serializer.serialize(key));
return serializer.deserialize(value);
}
});
return result;
}

@Override
public boolean expire(final String key, long expire) {
return redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}

@Override
public boolean remove(final String key) {
boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
connection.del(key.getBytes());
return true;
}
});
return result;
}
@Override
public Long incr(String key,long time){
long count = redisTemplate.opsForValue().increment(key, 1);
if (count == 1) {
//设置有效期一分钟
set(key,"1");
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return count;
}
}

至此限流的准备工作都做完了,测试一下ok,在controller方法中加上如下注解即可

@AccessLimit(seconds=second, maxCount=maxCount)

测试通过。

代码大部分是从网上copy过来的,我只是整理了一下,因为我是隔了好久才整理的,至于copy的哪位大神的代码我找不到了,如有冒犯,请见谅!

文章目录
  1. 1. 1.使用maven添加依赖库,本项目中使用的是:
  2. 2. 2.配置redis服务
  3. 3. 3.回到正题,目的是使用redis达到接口限流的效果。