当前位置: 首页 > news >正文

SpringBoot使用滑动窗口限流防止用户重复提交(自定义注解实现)

        在你的项目中,有没有遇到用户重复提交的场景,即当用户因为网络延迟等情况把已经提交过一次的东西再次进行了提价,本篇文章将向各位介绍使用滑动窗口限流的方式来防止用户重复提交,并通过我们的自定义注解来进行封装功能。

首先,导入相关依赖:

<!--        引入切面依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><scope>test</scope></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId></dependency>

然后,我们先写一下滑动窗口限流的逻辑:

//滑动窗口限流逻辑
public class RateLimiter {private static ConcurrentHashMap<String, Deque<Long>> requestTimestamps=new ConcurrentHashMap<>();public static boolean isAllowed(String userId,int timeWindow,int maxRequests){long now =System.currentTimeMillis();long windowStart=now -(timeWindow*1000);requestTimestamps.putIfAbsent(userId,new LinkedList<>());Deque<Long> timestamps=requestTimestamps.get(userId);synchronized (timestamps){// 移除窗口外的时间戳while(!timestamps.isEmpty()&& timestamps.peekFirst()<windowStart){timestamps.pollFirst();}// 如果时间戳数量小于最大请求数,允许访问并添加时间戳if(timestamps.size()<maxRequests){timestamps.addLast(now);return true;}else{return false;}}}
}
主要部分解释
1. 定义 requestTimestamps 变量

private static ConcurrentHashMap<String, Deque<Long>> requestTimestamps = new ConcurrentHashMap<>();

  • requestTimestamps 是一个并发的哈希映射,用于存储每个用户的请求时间戳。
  • 键(String)是用户ID。
  • 值(Deque<Long>)是一个双端队列,用于存储用户请求的时间戳(以毫秒为单位)。
2. isAllowed 方法

public static boolean isAllowed(String userId, int timeWindow, int maxRequests) {

  • 该方法接受三个参数:
    • userId:用户ID。
    • timeWindow:时间窗口,单位为秒。
    • maxRequests:时间窗口内允许的最大请求数。
  • 方法返回一个布尔值,表示用户是否被允许发出请求。
3. 获取当前时间和时间窗口开始时间

long now = System.currentTimeMillis(); long windowStart = now - (timeWindow * 1000);

  • now:当前时间,以毫秒为单位。
  • windowStart:时间窗口的开始时间,即当前时间减去时间窗口长度,以毫秒为单位。
4. 初始化用户的请求时间戳队列

requestTimestamps.putIfAbsent(userId, new LinkedList<>()); Deque<Long> timestamps = requestTimestamps.get(userId);

  • requestTimestamps.putIfAbsent(userId, new LinkedList<>()):如果 requestTimestamps 中没有该用户的记录,则为其初始化一个空的 LinkedList
  • timestamps:获取该用户对应的时间戳队列。
5. 同步时间戳队列

synchronized (timestamps) {

  • 同步块:对用户的时间戳队列进行同步,以确保线程安全。
6. 移除窗口外的时间戳

while (!timestamps.isEmpty() && timestamps.peekFirst() < windowStart) { timestamps.pollFirst(); }

  • 循环检查并移除队列中位于时间窗口之外的时间戳(即小于 windowStart 的时间戳)。
7. 检查请求数并更新时间戳队列

if (timestamps.size() < maxRequests) { timestamps.addLast(now); return true; } else { return false; }

  • 如果时间戳队列的大小小于 maxRequests,说明在时间窗口内的请求次数未超过限制:
    • 将当前时间戳添加到队列的末尾。
    • 返回 true,表示允许请求。
  • 否则,返回 false,表示拒绝请求。

接下来我们需要实现一个AOP切面,来实现我们的自定义注解

@Component
@Aspect
public class RateLimitInterceptor {
//    private HashMap<String,String> info;@Autowiredprivate RedisTemplate<String,String> redisTemplate;@Around("@annotation(rateLimit)")public Object interceptor(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {String userid= redisTemplate.opsForValue().get("loginId");   //获取用户IDSystem.out.println("userid:"+userid);int timeWindow=rateLimit.timeWindow();int maxRequests=rateLimit.maxRequests();if(RateLimiter.isAllowed(userid,timeWindow,maxRequests)){return joinPoint.proceed();}else{throw new RepeatException("访问过于频繁,请稍后再试");}}
}

        获取用户ID的逻辑需要根据你的项目实际情况进行编写,我这里是把id存在redis里面的,但是也是存在问题的,读者可以尝试使用RabbitMQ进行实现。

然后,自定义一个注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {int timeWindow() default 60; // 时间窗口大小,单位为秒int maxRequests() default 10;  //最大请求次数
}

        以上代码写好之后,其实整个关键的代码就完成了,你可以随便在你的项目中找一个接口试一下,如下:

maxRequests表示在timeWindow时间内的最大请求数

        结果如下,当然如果需要在前台显示,可以稍微改一下异常的处理方式,让提示信息能在前台显示:

相关文章:

SpringBoot使用滑动窗口限流防止用户重复提交(自定义注解实现)

在你的项目中&#xff0c;有没有遇到用户重复提交的场景&#xff0c;即当用户因为网络延迟等情况把已经提交过一次的东西再次进行了提价&#xff0c;本篇文章将向各位介绍使用滑动窗口限流的方式来防止用户重复提交&#xff0c;并通过我们的自定义注解来进行封装功能。 首先&a…...

ravynOS 0.5.0 发布 - 基于 FreeBSD 的 macOS 兼容开源操作系统

ravynOS 0.5.0 发布 - 基于 FreeBSD 的 macOS 兼容开源操作系统 ravynOS - 一个旨在提供 macOS 的精致性和 FreeBSD 的自由度的操作系统 请访问原文链接&#xff1a;https://sysin.org/blog/ravynos/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页…...

韩国面临的本地化挑战

西方文化&#xff0c;尤其是美国电影、音乐和游戏&#xff0c;对韩国也产生了同样大的影响。众所周知&#xff0c;这个国家与外国产品的关系更加开放。然而&#xff0c;游戏在这里仍然受到审查&#xff0c;所以最好避免与朝鲜、日本等有关的分裂性政治主题。否则&#xff0c;你…...

Linux内存从0到1学习笔记(8.17 SMMU Fault调试方法)

写在前面 通过前面的介绍,我们知道了SMMU实际上是一个针对外设的MMU。它作为一个硬件IP被设备执行DMA操作时使用。 再来简单回顾下SMMU的工作流程: 外设 ---> DMA操作 ---> SMMU ---> Memory 也就是说,通常情况下驱动程序会先分配DMA Buffer ---> 然后执行S…...

讲座学习截图——《CAD/CAE/CAM几何引擎-软件概述》(一)

目录 引出CAD/CAE/CAM几何引擎-软件概述 郝建兵CADCAECAM 几何模型内核ACIS 两个老大之一Open CascadeParasolid 两个老大之一Autodesk的内核 总结其他自定义信号和槽1.自定义信号2.自定义槽3.建立连接4.进行触发 自定义信号重载带参数的按钮触发信号触发信号拓展 lambda表达式…...

鸿蒙开发系统基础能力:【@ohos.hichecker (检测模式)】

检测模式 HiChecker可以作为应用开发阶段使用的检测工具&#xff0c;用于检测代码运行过程中部分易忽略的问题&#xff0c;如应用线程出现耗时调用、应用进程中Ability资源泄露等问题。开发者可以通过日志记录或进程crash等形式查看具体问题并进行修改&#xff0c;提升应用的使…...

WordPress CDN是什么?CDN有什么作用?

您想让您的网站加载速度更快吗&#xff1f; 网站所有者希望网站加载速度快&#xff0c;内容丰富&#xff0c;功能强大&#xff0c;吸引用户。然而&#xff0c;添加这些功能可能会降低网站速度&#xff0c;难以快速向全球用户提供内容。 这就是为什么许多WordPress网站使用 CDN…...

【containerd】Containerd高阶命令行工具nerdctl

前言 对于习惯了使用docker cli的用户来说&#xff0c;containerd的命令行工具ctr使用起来不是很顺手&#xff0c;此时别慌&#xff0c;还有另外一个命令行工具项目nerdctl可供我们选择。 nerdctl是一个与docker cli风格兼容的containerd的cli工具。 nerdctl已经作为子项目加入…...

Spring+SpringMVC+MyBatis整合

目录 1.SSM介绍1.1 什么是SSM&#xff1f;1.2 SSM框架1.2.1 Spring1.2.2 SpringMVC1.2.3 MyBatis 2.SSM框架整合2.1 建库建表2.2 创建工程2.3 pom.xml2.4 log4j.properties2.5 db.properties2.6 applicationContext-dao.xml2.7.applicationContext-tx.xml2.8 applicationContex…...

springboot+vue+mybatis穷游管理系统+PPT+论文+讲解+售后

随着现在网络的快速发展&#xff0c;网上管理系统也逐渐快速发展起来&#xff0c;网上管理模式很快融入到了许多企业的之中&#xff0c;随之就产生了“基于vue的穷游管理系统”&#xff0c;这样就让基于vue的穷游管理系统更加方便简单。 对于本基于vue的穷游管理系统的设计来说…...

ClickHouse备份方案

ClickHouse备份方案主要包括以下几种方法&#xff1a; 一、使用clickhouse-backup工具&#xff1a; &#xff08;参考地址&#xff1a;https://blog.csdn.net/qq_43510111/article/details/136570850&#xff09; **安装与配置&#xff1a;**首先从GitHub获取clickhouse-bac…...

windows启用和禁用内存压缩

windows内存压缩 Windows操作系统的内存压缩是一种通过压缩和解压缩内存页面来减少内存使用量的技术。当系统的内存使用达到一定阈值时&#xff0c;Windows会将不常用的内存页面压缩为一个稳定的压缩文件&#xff0c;以释放更多的内存空间。 内存压缩的主要目的是减少页面交换…...

MATLAB-振动问题:单自由度无阻尼振动系统受迫振动

一、基本理论 二、MATLAB实现 令式&#xff08;1.3&#xff09;中A0 2&#xff0c;omega0 30&#xff0c;omega 40&#xff0c;matlab程序如下&#xff1a; clear; clc; close all;A0 2; omega0 30; omega 40; t 0:0.02:5; y A0 * sin( (omega0 - omega) * t /2) .* s…...

示例:WPF中应用DependencyPropertyDescriptor监视依赖属性值的改变

一、目的&#xff1a;开发过程中&#xff0c;经常碰到使用别人的控件时有些属性改变没有对应的事件抛出&#xff0c;从而无法做处理。比如TextBlock当修改了IsEnabled属性我们可以用IsEnabledChanged事件去做对应的逻辑处理&#xff0c;那么如果有类似Background属性改变我想找…...

链家房屋数据爬取与预处理-大数据采集与预处理课程设计

芜湖市链家二手房可视化平台 成品展示 重点说明 1.数据特征数量和名称、数据量 数据特征数量&#xff1a;14&#xff1b; 名称&#xff1a;小区名、价格/万、地区、房屋户型、所在楼层、建筑面积/平方米、户型结构、套内面积、建筑类型、房屋朝向、建筑结构、装修情况、梯户…...

一种502 bad gateway nginx/1.18.0的解决办法

背景:上线的服务突然挂掉了 step1&#xff0c;去后端日志查看&#xff0c;发现并无异常&#xff0c;就是请求无法被接收 step2&#xff0c;查看了nginx的错误日志&#xff0c;发现该文件为空 step3&#xff0c;查看了niginx的运行日志&#xff0c;发现了以下问题 [error] 38#…...

二叉树第一期:树与二叉树的概念

一、树 1.树的定义 与线性表不同&#xff0c;树是一种非线性的数据结构&#xff0c;由N(N>0)个结点组成的具有层次关系的集合&#xff1b;因其形状类似生活中一颗倒挂着的树&#xff0c;故将其数据结构称为树。 2.树的相关概念 根结点 没有前驱的结点&#xff0c;称为根…...

vue跨域问题,请注意你的项目是vue2还是vue3

uniapp跨域设置了&#xff0c;但还是有问题 uniapp设置代理后还是无法请求后端接口vue2项目设置代理vue3项目设置代理 uniapp设置代理后还是无法请求后端接口 如果你在possman&#xff0c;apifox上测试接口都没有问题&#xff0c;但是在hbuild项目中设置代理后&#xff0c;还是…...

大厂晋升学习方法一:海绵学习法

早晨 30 分钟 首先&#xff0c;我们可以把起床的闹钟提前 30 分钟&#xff0c;比如原来 07:30 的闹钟可以改为 07:00。不用担心提前 30 分钟起床会影响休息质量&#xff0c;习惯以后&#xff0c;早起 30 分钟不但不会影响一天的精力&#xff0c;甚至可能反而让人更有精神。早起…...

【ARMv8/v9 GIC 系列 4.2 -- GIC CPU Interface 详细介绍】

文章目录 GIC CPU Interface 介绍CPU Interface 主要寄存器 GIC CPU Interface 介绍 A 系列处理器提供 5个管脚来实现中断&#xff0c;分别是&#xff1a; nIRQ&#xff1a;物理普通中断nFIQ&#xff1a;物理快速中断nVIRQ&#xff1a;虚拟普通中断nVFIQ&#xff1a;虚拟快速…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

多模态图像修复系统:基于深度学习的图片修复实现

多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...