本文将介绍在spring项目中自定义注解,借助redis实现接口的限流

自定义注解类


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* 基于注解的请求限制
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AccessLimit {
/**
* 请求限制数
* @return
*/
int limit(); /**
* 时间范围
* @return
*/
int timeScope(); }

使用注解

我们在需要进行接口防刷的类或者方法上加上该注解即可,


/**
* 得到秒杀地址
* 由于秒杀地址较为重要和敏感,为了防止恶意用户刷接口,
* 我们将秒杀接口作为动态的
* @param user
* @param goodsId
* @param tryCode
* @return
*/
@GetMapping("/path")
@ResponseBody
@AccessLimit(limit = 5, timeScope = 5) // 限制5秒内只能请求5次
public Result<String> getMiaoshaPath(HttpServletRequest request, User user, long goodsId, String tryCode) {
// 验证码校验
Boolean verifyPass = kaptchaService.imgVerifyCode(user, goodsId, tryCode);
if (!verifyPass) {
log.info("【执行秒杀】-- 验证码错误");
throw new FlashSaleException(KAPTCHA_VERIFY_FAIL);
}
String path = miaoshaService.createPath(user, goodsId);
return Result.success(path);
};

使用拦截器,在拦截方法时拿到注解上的属性

 @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 从redis中取到值
Cookie cookie = CookieUtil.get(request, Constants.Cookie.TOKEN);
if (cookie == null) {
throw new FlashSaleException(AuthFailEnum.COOKIE_HAVE_NO_TOKEN);
}
StringRedisTemplate redisTemplate = ApplicationContextHolder.get().getBean("stringRedisTemplate", StringRedisTemplate.class);
String userStr = redisTemplate.opsForValue().get(cookie.getValue());
if (StringUtils.isEmpty(userStr)) {
throw new FlashSaleException(AuthFailEnum.REDIS_HAVE_NOT_TOKEN);
}
User user = JSON.parseObject(userStr, User.class);
UserContextHolder.set(user);
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
// 拿到注解的内容
AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
if (accessLimit == null) {
// 不需要限流验证
return true;
} else {
// 需要限流验证
int limit = accessLimit.limit();
int timeScope = accessLimit.timeScope();
// 次数校验(借助redis实现基于用户的限流验证)
String requestURI = request.getRequestURI();
final String redisKey = Constants.Cache.PATH_COUNT_PREFIX + user.getId() + ":" + requestURI;
String currentCount = redisTemplate.opsForValue().get(redisKey);
if (!StringUtils.isEmpty(currentCount)) {
int count = Integer.valueOf(currentCount);
if (count < limit) {
redisTemplate.opsForValue().increment(redisKey, 1);
} else {
// 访问过于频繁
throw new FlashSaleException(PATH_LIMIT_REACHED);
}
} else {
redisTemplate.opsForValue().set(redisKey, "1", timeScope, TimeUnit.SECONDS);
}
}
}
UserContextHolder.set(user);
renewExpiretime(response, cookie, userStr);
return true;
}

总结

 在实现了上述代码后,当我们访问到带有AccessLimit注解的方法或类时,只要拦截器拦截了该请求,就能通过getMethodAnnotation()拿到注解上的limit和timeScope属性,然后借助redis实现限流;比如某些接口我们可能想要2秒只能访问1次,那么就把limit=1 timeScope=2,某些接口我们想要限制1分钟访问10次,就把limit=10, timeScope=60

spring中实现基于注解实现动态的接口限流防刷的更多相关文章

  1. SpringBoot使用自定义注解+AOP+Redis实现接口限流

    为什么要限流 系统在设计的时候,我们会有一个系统的预估容量,长时间超过系统能承受的TPS/QPS阈值,系统有可能会被压垮,最终导致整个服务不可用.为了避免这种情况,我们就需要对接口请求进行限流. 所以 ...

  2. 使用 Spring 2.5 基于注解驱动的 Spring MVC

    http://www.ibm.com/developerworks/cn/java/j-lo-spring25-mvc/ 概述 继 Spring 2.0 对 Spring MVC 进行重大升级后,Sp ...

  3. 使用 Spring 2.5 基于注解驱动的 Spring MVC--转

    概述 继 Spring 2.0 对 Spring MVC 进行重大升级后,Spring 2.5 又为 Spring MVC 引入了注解驱动功能.现在你无须让 Controller 继承任何接口,无需在 ...

  4. JavaEE开发之Spring中的条件注解组合注解与元注解

    上篇博客我们详细的聊了<JavaEE开发之Spring中的多线程编程以及任务定时器详解>,本篇博客我们就来聊聊条件注解@Conditional以及组合条件.条件注解说简单点就是根据特定的条 ...

  5. JavaEE开发之Spring中的条件注解、组合注解与元注解

    上篇博客我们详细的聊了<JavaEE开发之Spring中的多线程编程以及任务定时器详解>,本篇博客我们就来聊聊条件注解@Conditional以及组合条件.条件注解说简单点就是根据特定的条 ...

  6. 第5章—构建Spring Web应用程序—关于spring中的validate注解后台校验的解析

    关于spring中的validate注解后台校验的解析 在后台开发过程中,对参数的校验成为开发环境不可缺少的一个环节.比如参数不能为null,email那么必须符合email的格式,如果手动进行if判 ...

  7. Spring 中aop切面注解实现

    spring中aop的注解实现方式简单实例   上篇中我们讲到spring的xml实现,这里我们讲讲使用注解如何实现aop呢.前面已经讲过aop的简单理解了,这里就不在赘述了. 注解方式实现aop我们 ...

  8. spring中使用@Async注解进行异步处理

    引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3. ...

  9. Spring中的常用注解

    Spring中的常用注解 1.@Controller 标识一个该类是Spring MVC controller处理器,用来创建处理http请求的对象.

随机推荐

  1. PMP--2.2 效益管理计划

    一.文件背景概述 ​​​1. 所需文件/数据 制定效益管理计划需要使用商业论证和需求评估中的数据和信息,例如,成本效益分析数据. 成本效益分析数据是在商业论证和需求评估中得到的,在成本效益分析中已经把 ...

  2. 关于PHP连接上MySQL但不能插入数据

    出现这种情况,有三种可能 1.SQL语句有问题 insert into table_name(field1,field2...) values(value1,value2...); 先在MySQL中粘 ...

  3. Asciidoctor-pdf生成pdf文件

    本文使用asciidoc语法编写. = Asciidoctor-pdf生成pdf文件 Pinnsvin Pinnsvin@163.com v1.0 {docdate} :plantuml-server ...

  4. PPT、Word、Excel模板免费下载

    本篇文章可能只有寥寥数字,但他的作用可能很大,可能帮助到很多朋友.本人喜欢搜集一些资源,也爱免费分享,因为好东西我藏不住,总感觉分享出来更快乐. 网址:https://www.bangongziyua ...

  5. linux--工具进阶

    linux学习 看完了基础篇,下面来看进阶篇 我好想哭看这的时候,好多只是听说过,但完全没有试过,感觉自己懂得有点少,就是缺乏一些知识储备,也就是必须知道了某些或学过了某些知识才适合来看这一部分,看得 ...

  6. [大数据技术]Kettle从CSV文件读取清洗后到MySQL中文乱码问题

    首先要知道CSV文件的编码格式 然后在文件输入编码选择编码格式, 第二步,在每个转换或者作业的DB连接中选择选项,并添加如下内容: 中文乱码问题得到解决

  7. phpcms抛出的二维数组转移到js,js中for....in遍历数组,用“.”连接来读出一维数组值

    直切正题: 1.phpcms在模版中读出数组有很多中方法,如,{pc:content action="lists"}或{pc:get sql=""},经过{lo ...

  8. mysql引擎介绍

    mysql存储引擎介绍: 插拔式的插件方式 存储引擎是指定在表上的,即一个库中的每一个表都可以指定专用的存储引擎 不管采用什么样的存储引擎,都会在数据区产生对应的一个frm文件(表结构定义描述文件) ...

  9. Keras高层API之Metrics

    在tf.keras中,metrics其实就是起到了一个测量表的作用,即测量损失或者模型精度的变化.metrics的使用分为以下四步: step1:Build a meter acc_meter = m ...

  10. JS:JS中常见的 “函数名 is not a function” 错误

    js中常见的错误,例如Uncaught TypeError: x is not a function 其原因除了函数本身有错之外,还有一种很奇怪的情况:函数本身没有错,但是运行时就是不能正常运行.这种 ...