JAVA:Spring Boot 实现接口防抖的技术指南

1、简述

在 Web 应用中,接口防抖是一种常见的技术手段,用于防止客户端在短时间内多次触发同一接口,从而减轻服务器的负担和防止重复操作。本文将介绍如何在 Spring Boot 项目中实现接口防抖功能,并通过实例展示其应用场景。

在这里插入图片描述

2、防抖

2.1 什么是接口防抖?

接口防抖(Debouncing)是一种在用户频繁触发操作时,通过延迟响应来减少接口调用次数的技术。它通过设定一个时间窗口,在该时间窗口内,如果同一接口被多次调用,则只会执行最后一次调用的操作,其他调用将被忽略。

2.2 为什么需要接口防抖?

在实际开发中,用户可能会由于网络延迟或重复点击等原因频繁触发接口调用,导致服务器压力增大,甚至引发重复的数据库操作。接口防抖可以有效地避免这些问题,从而提升应用的性能和用户体验。

在这里插入图片描述

3、时间戳实现防抖

3.1 使用注解和 AOP 实现防抖逻辑

我们可以通过自定义注解和 Spring AOP(面向切面编程)来实现接口防抖功能。首先,创建一个自定义注解 @Debounce,用于标记需要防抖的接口。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Debounce {
    long delay() default 1000; // 默认防抖时间为 1 秒
}
3.2 实现防抖切面逻辑

接下来,创建一个 AOP 切面类,拦截带有 @Debounce 注解的方法,并实现防抖逻辑。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Aspect
@Component
public class DebounceAspect {

    private final Map<String, Long> requestTimestamps = new ConcurrentHashMap<>();

    @Around("@annotation(debounce)")
    public Object around(ProceedingJoinPoint joinPoint, Debounce debounce) throws Throwable {
        String key = joinPoint.getSignature().toString();
        long currentTime = System.currentTimeMillis();

        Long lastTime = requestTimestamps.get(key);
        if (lastTime != null && (currentTime - lastTime) < debounce.delay()) {
            // 如果在防抖时间内,则忽略这次调用
            return null;
        }

        // 更新上次调用的时间戳
        requestTimestamps.put(key, currentTime);

        // 执行目标方法
        return joinPoint.proceed();
    }
}

这个切面类中使用 ConcurrentHashMap 来记录每个接口的最近调用时间,并在调用前判断是否在防抖时间内。如果在防抖时间内则忽略这次调用,否则更新调用时间并继续执行接口逻辑。

3.3 应用防抖注解

在实际使用中,只需要将 @Debounce 注解添加到需要防抖的接口方法上即可。例如:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class DebounceController {

    @GetMapping("/submit")
    @Debounce(delay = 2000)
    public String submitForm() {
        return "表单提交成功";
    }
}

在这个例子中,当用户在 2 秒内多次触发 /api/submit 接口时,只有第一次请求会被处理,其余请求将被忽略。

4、Redis实现防抖

Redis 是一个高性能的内存数据库,具有极快的读写速度和丰富的数据类型。使用 Redis 可以非常高效地实现防抖功能,因为它支持键的过期时间功能,可以根据需要灵活设置请求的限制时间。

4.1 配置

首先,需要在 pom.xml 中引入 Spring Boot 的 Redis 依赖:

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

在 application.yml 或 application.properties 文件中配置 Redis 连接信息:

spring:
  redis:
    host: localhost
    port: 6379
    # 如果使用密码,可以添加以下配置
    # password: yourpassword
4.2 创建 Redis 工具类

为了方便操作 Redis,可以创建一个工具类来封装常用的方法:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class RedisUtil {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 设置键值对,并设置过期时间
     *
     * @param key     键
     * @param value   值
     * @param timeout 超时时间
     * @param unit    时间单位
     */
    public void set(String key, String value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    /**
     * 检查键是否存在
     *
     * @param key 键
     * @return 如果存在返回 true,否则返回 false
     */
    public boolean hasKey(String key) {
        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
    }
}
4.3 实现防抖功能

接下来,我们将实现一个拦截器,用于在请求到达控制器之前进行防抖处理。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class DebounceInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisUtil redisUtil;

    private static final long DEBOUNCE_TIME = 2; // 防抖时间(秒)

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String key = "debounce:" + request.getSession().getId() + ":" + request.getRequestURI();
        
        if (redisUtil.hasKey(key)) {
            response.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);
            return false; // 拦截请求
        }

        // 设置防抖时间
        redisUtil.set(key, "1", DEBOUNCE_TIME, TimeUnit.SECONDS);
        return true; // 继续执行请求
    }
}

这个拦截器会为每个请求生成一个唯一的键(通过会话 ID 和请求 URI 组合),然后检查 Redis 中是否已经存在该键。如果存在,表示该请求在短时间内已被发起过,将返回 429(请求过多)状态码并拦截请求。否则,拦截器将继续处理请求,并将请求信息存储在 Redis 中,设置过期时间。

4.4 测试防抖功能

创建一个简单的控制器来测试防抖功能:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    @GetMapping("/api/test")
    public String testDebounce() {
        return "Request successful!";
    }
}

启动应用程序,然后在短时间内多次访问 /api/test 接口。你应该会看到第一次请求返回 “Request successful!”,后续快速的请求将被拦截,并返回状态码 429。

5、总结

接口防抖是一种简单而有效的手段,用于提高系统的健壮性和用户体验。在 Spring Boot 项目中,通过自定义注解和 AOP 可以轻松实现防抖功能。本文通过实例展示了如何将接口防抖应用于实际开发中,从而避免由于频繁调用导致的服务器压力和重复操作。

通过这种方法,你可以有效地减少接口的无效调用次数,优化系统性能。如果有其他需求或进一步探讨的内容,欢迎随时交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/925021.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

连续变量的 交叉熵 如何计算 python tensorflow

连续变量的交叉熵通常在机器学习中的回归问题中使用&#xff0c;但它也可以用于分类问题&#xff0c;当概率分布是连续的时。连续变量的交叉熵计算公式如下&#xff1a; 设 \( p(x) \) 是真实概率密度函数&#xff0c;\( q(x) \) 是预测概率密度函数&#xff0c;交叉熵 \( H(p…

gitee:创建仓库,存入本地文件至仓库

一、git下载 git:下载与安装-CSDN博客https://blog.csdn.net/weixin_46001736/article/details/144107485?sharetypeblogdetail&sharerId144107485&sharereferPC&sharesourceweixin_46001736&spm1011.2480.3001.8118 二、创建仓库 1、主页面->右上角新增…

burpsuite(2)最新版burpsuite安装教程

一、安装Java 1.安装jdk21&#xff0c;直接官网下载 下载链接&#xff1a;Java21 2.cmd 输出java&#xff08;查看java是否已经被安装&#xff09; 3.java -version&#xff08;查看java版本&#xff09; 二、安装burpsuite 4.下载burpsuite最新版本&#xff0c;选择jar方式…

Java 语言的起源发展与基本概念(JDK,JRE,JVM)

Java语言的起源 源起 Java语言最初是由Sun Microsystems公司&#xff08;该公司于2009年被Oracle公司收购&#xff09;开发的一种编程语言。其创造者是詹姆斯高斯林&#xff08;James Gosling&#xff09;&#xff0c;他是一位加拿大计算机科学家。其前身名为Oak&#xff08;橡…

ELK(Elasticsearch + logstash + kibana + Filebeat + Kafka + Zookeeper)日志分析系统

文章目录 前言架构软件包下载 一、准备工作1. Linux 网络设置2. 配置hosts文件3. 配置免密登录4. 设置 NTP 时钟同步5. 关闭防火墙6. 关闭交换分区7. 调整内存映射区域数限制8. 调整文件、进程、内存资源限制 二、JDK 安装1. 解压软件2. 配置环境变量3. 验证软件 三、安装 Elas…

Maven、JAVAWeb、Servlet

知识点目标 1、MavenMaven是什么Maven项目的目录结构Maven的Pom文件Maven的命令Maven依赖管理Maven仓库JavaWeb项目 2.网络基础知识 3、ServletMaven Maven是什么 Maven是Java的项目管理工具&#xff0c;可以构建&#xff0c;打包&#xff0c;部署项目&#xff0c;还可以管理…

26页PDF | 数据中台能力框架及评估体系解读(限免下载)

一、前言 这份报告详细解读了数据中台的发展历程、核心概念、能力框架及成熟度评估体系。它从阿里巴巴的“大中台&#xff0c;小前台”战略出发&#xff0c;探讨了数据中台如何通过整合企业内部的数据资源和能力&#xff0c;加速业务迭代、降低成本&#xff0c;并推动业务增长…

使用R的数据包快速获取、调用各种地理数据

数据一直是科学研究绕不开的话题&#xff0c;为了方便快捷的获取各种地理数据&#xff0c;许多R包被开发出来&#xff0c;今天介绍一些方便快捷的数据R包。 rnaturalearth 包使 Natural Earth 数据可用。自然地球特征包括 1&#xff1a;10m、1&#xff1a;50m 和 1&#xff1a…

docker的joinsunsoft/docker.ui修改密码【未解决】

docker的joinsunsoft/docker.ui修改密码 前言 这个挺遗憾的&#xff0c;个人能力不足。想修改密码是不可能了。 因为&#xff0c;系统的密码加密规则不知道。 目前了解到的内容是&#xff1a; 地址是&#xff1a;https://hub.docker.com/r/joinsunsoft/docker.ui服务是用go语…

启动SpringBoot

前言&#xff1a;大家好我是小帅&#xff0c;今天我们来学习SpringBoot 文章目录 1. 环境准备2. Maven2.1 什么是Maven2.2 创建⼀个Maven项⽬2.3 依赖管理2.3.1 依赖配置2.3.2 依赖传递2.3.4 依赖排除2.3.5 Maven Help插件&#xff08;plugin&#xff09; 2.4 Maven 仓库2.6 中…

SQL进阶——JOIN操作详解

在数据库设计中&#xff0c;数据通常存储在多个表中。为了从这些表中获取相关的信息&#xff0c;我们需要使用JOIN操作。JOIN操作允许我们通过某种关系&#xff08;如相同的列&#xff09;将多张表的数据结合起来。它是SQL中非常重要的操作&#xff0c;广泛应用于实际开发中。本…

JVM(JAVA虚拟机)内存溢出导致内存不足,Java运行时环境无法继续

1、先贴出服务最后打印出来的日志&#xff0c;意思就是给虚拟机分配的内存被用完了&#xff0c;没有可用的内存了&#xff0c;服务运行不了了&#xff0c;被动停服了。详细的日志记录在了/home/user/zx/tomcat/apache-tomcat-8.5.82/bin/hs_err_pid147951.log文件里。 Java Ho…

组成无重复数字的三位数

#include <stdio.h>int main() {int count 0;// 利用三重循环遍历所有可能的百位、十位、个位取值情况for (int bai 1; bai < 4; bai) {for (int shi 1; shi < 4; shi) {for (int ge 1; ge < 4; ge) {if (bai! shi && bai! ge && shi! ge) …

移远通信携手紫光展锐,以“5G+算力”共绘万物智联新蓝图

11月26日&#xff0c;2024紫光展锐全球合作伙伴大会在上海举办。作为紫光展锐重要的合作伙伴&#xff0c;移远通信应邀参会。 在下午的物联网生态论坛上&#xff0c;移远通信产品总监胡勇华作题为“5G与算力双擎驱动 引领智联新未来”的演讲&#xff0c;深度剖析了产业发展的趋…

Ubuntu 服务器部署 Tomcat 并配置 SSL/TLS 证书

本文目录 准备登陆云服务器安装 Java下载 tomcat 包配置防火墙浏览器访问 Tomcat 默认页面以服务的形式运行 Tomcat创建 Tomcat 用户和组创建 systemd 服务文件启动 tomcat 服务 Tomcat webapps 文件目录部署一个静态网站tomcat 的配置文件 将域名解析到服务器Tomcat 配置 SSL/…

【仓颉学习02】编译后运行报错:“由于找不到libcanjie-runtime.dll,无法继续执行代码。重新安装程序可能会解决此问题。”

敲了段《仓颉语言实践》&#xff08;张磊著&#xff09;书上的代码&#xff0c;如下&#xff1a; package test //coding:utf-8struct Employee{var name:Stringprivate var realSalary:Float64public Employee(name:String,realSalary:Float64){this.namenamethis.realSalary…

基于Linux操作系统的DNS服务器实验

实验6 DNS服务器 一、实验目的 熟练掌握DNS服务器的原理、配置过程与应用。 二、实验环境 硬件&#xff1a;PC电脑一台&#xff0c;网络正常。 配置&#xff1a;win10系统&#xff0c;内存大于8G &#xff0c;硬盘500G及以上。 软件&#xff1a;VMware、Ubuntu16.04。 三、…

Taro 鸿蒙技术内幕系列(三) - 多语言场景下的通用事件系统设计

基于 Taro 打造的京东鸿蒙 APP 已跟随鸿蒙 Next 系统公测&#xff0c;本系列文章将深入解析 Taro 如何实现使用 React 开发高性能鸿蒙应用的技术内幕 背景 在鸿蒙生态系统中&#xff0c;虽然原生应用通常基于 ArkTS 实现&#xff0c;但在实际研发过程中发现&#xff0c;使用 C…

万能门店小程序管理系统 onepic_uploade 任意文件上传漏洞复现

0x01 产品简介 万能门店小程序管理系统是一款功能强大的工具,旨在为各行业商家提供线上线下融合的全方位解决方案。是一个集成了会员管理和会员营销两大核心功能的综合性平台。它支持多行业使用,通过后台一键切换版本,满足不同行业商家的个性化需求。该系统采用轻量后台,搭…

STM32-C语言基础知识

C语言基础知识 stdint.h简介 给寄存器某个位赋值 给位6赋值为1流程&#xff1a;先清0&#xff0c;再赋值 带参数的宏定义 建议使用do {…}while(0)来构造宏定义 条件编译 条件编译后面必须跟宏语句&#xff0c;如#if _LED_H 指针使用常见的2大问题 1、未初始化 2、越界使…