SpringBoot+Redis實現(xiàn)接口限流
在這之前對redis一無所知,做的過程都是參考網(wǎng)上的資料,如果有冒犯之處請見諒,整理一下,希望對大家都用。
1.使用maven添加依賴庫,本項目中使用的是:
<dependency>
???<groupId>org.springframework.bootgroupId>
???<artifactId>spring-boot-starter-data-redisartifactId>
???<version>2.1.4.RELEASEversion>
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();
//關(guān)于key的生成規(guī)則可以自己定義?本項目需求是對每個方法都加上限流功能,如果你只是針對ip地址限流,那么key只需要只用ip就好
????????????????String?key?=?????SystemUtil.getClientIp(httpServletRequest)+hm.getMethod().getName();
??????????????
????????????????//從redis中獲取用戶訪問的次數(shù)
????????????????try?{
????????????????????long?q?=?redisService.incr(key,?seconds);//此操作代表獲取該key對應的值自增1后的結(jié)果
????????????????????if?(q?>?maxCount)?{
????????????????????????//加1
????????????????????????render(httpServletResponse,?new?ResponseMsg(0,?"請求過于頻繁,請稍候再試",?null));?//這里的CodeMsg是一個返回參數(shù)
????????????????????????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存數(shù)據(jù)
?????*?@param?key
?????*?@param?value
?????*?@return
?????*/
????boolean?set(String?key,?String?value);
?
????/**
?????*?get獲取數(shù)據(jù)
?????*?@param?key
?????*?@return
?????*/
????String?get(String?key);
?
????/**
?????*?設置有效天數(shù)
?????*?@param?key
?????*?@param?expire
?????*?@return
?????*/
????boolean?expire(String?key,?long?expire);
?
????/**
?????*?移除數(shù)據(jù)
?????*?@param?key
?????*?@return
?????*/
????boolean?remove(String?key);
?
????/**
?????*?獲取自增1后的?值
?????*?@param?key
?????*?@param?time
?????*?@return
?????*/
????Long?incr(String?key,long?time);
}
redisservice的實現(xiàn)類
@Service("redisService")
public?class?RedisServiceImpl?implements?RedisService?{
?
?
????@Resource
????private?RedisTemplate?redisTemplate;
?
?
????@Override
????public?boolean?set(final?String?key,?final?String?value)?{
????????boolean?result?=?redisTemplate.execute(new?RedisCallback()?{
????????????@Override
????????????public?Boolean?doInRedis(RedisConnection?connection)?throws?DataAccessException?{
????????????????RedisSerializer?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()?{
????????????@Override
????????????public?String?doInRedis(RedisConnection?connection)?throws?DataAccessException?{
????????????????RedisSerializer?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()?{
????????????@Override
????????????public?Boolean?doInRedis(RedisConnection?connection)?throws?DataAccessException?{
????????????????RedisSerializer?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)
測試通過。
代碼大部分是從網(wǎng)上copy過來的,我只是整理了一下,因為我是隔了好久才整理的,至于copy的哪位大神的代碼我找不到了,如有冒犯,請見諒!
來源:blog.csdn.net/qq_34963282/article/
details/89489009
END
推薦閱讀 一鍵生成Springboot & Vue項目!【畢設神器】
Java可視化編程工具系列(一)
Java可視化編程工具系列(二)
順便給大家推薦一個GitHub項目,這個 GitHub 整理了上千本常用技術(shù)PDF,絕大部分核心的技術(shù)書籍都可以在這里找到,
GitHub地址:https://github.com/javadevbooks/books
電子書已經(jīng)更新好了,你們需要的可以自行下載了,記得點一個star,持續(xù)更新中..
評論
圖片
表情

