Redis接口访问优化

news2024/10/1 8:15:09

说明:之前写过一篇使用Redis接口访问的博客,如下。最近有相关需求,把代码拿出来后,做了一些优化,挺有意思的,本文介绍在原基础上

  • 使用Redis实现接口防抖

优化

总的来说,这次使用Redis实现接口防抖,增加了一个时间段参数,可以限制接口在某个时间段内,访问不能超过多少次。如下:

(自定义注解,打在接口上)

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 LimitAccess {

    /**
     * 限制访问的key
     * @return
     */
    String key();

    /**
     * 限制访问次数
     * @return
     */
    int times();

    /**
     * 时间段
     * @return
     */
    int duration();
}

(切面,实现限制访问)

import com.hezy.annotation.LimitAccess;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;

/**
 * AOP类(通知类)
 */
@Component
@Aspect
@Log4j2
public class LimitAspect {

    @Value("${access.enable:false}")
    private boolean enable;

    @Autowired
    private RedisTemplate redisTemplate;

    @Pointcut("@annotation(com.hezy.annotation.LimitAccess)")
    public void pt(){};

    @Around("pt()")
    public Object aopAround(ProceedingJoinPoint pjp) throws Throwable {
        // 设置一个开关,控制是否执行
        if (!enable) {
            return pjp.proceed();
        }
        // 获取切入点上面的自定义注解
        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;

        // 获取方法上面的注解
        LimitAccess limitAccess = methodSignature.getMethod().getAnnotation(LimitAccess.class);
        // 获取注解上面的属性值
        int limit = limitAccess.times();
        String key = limitAccess.key();
        int duration = limitAccess.duration();

        // 递增键的值,如果键不存在则初始化为1
        Long currentCount = redisTemplate.opsForValue().increment(key, 1);

        // 如果键是新创建的,设置过期时间
        if (currentCount != null && currentCount == 1) {
            redisTemplate.expire(key, duration, TimeUnit.SECONDS);
        }

        // 检查是否超过限制
        if (currentCount != null && currentCount > limit) {
            log.info("访问过于频繁: " + pjp.toLongString());
            throw new RuntimeException("访问过于频繁");
        }
        return pjp.proceed();
    }
}

(使用,在对应的接口上,打上注解,填上数值,如下表示,1秒内不能访问超过3次)

    @LimitAccess(key = "test", times = 3, duration = 1)
    @GetMapping
    public String test() {
        return demoService.test();
    }

另外,在代码中加了一个开关,可在配置文件中设置此配置,表示开启或者关闭,默认是关闭的

access:
  enable: true

启动项目,测试一下

在这里插入图片描述

思考

以上代码,有两点需要思考:

  • 注解能不能加在Service层的方法上,加了有没有用?另外加了会不会让声明式事务失效?

  • 这个限制,没有到用户的维度,也就是说所有的用户,只要在一个时间段内访问超过次数就限制,这显然是不行的。有什么办法吗?

第一点,我测试过,注解可以加在Service层方法上,是可以的,不会让事务失效,如下:

    @LimitAccess(key = "deleteUserById", times = 3, duration = 1)
    @Transactional
    @Override
    public void deleteUserById(Integer id) {
        // 删除用户
        userMapper.deleteUserById(id);
        
        int i = 1 / 0;

        // 删除用户对应的角色
        userMapper.deleteUserRoleMapper(id);
    }

接口限制,事务,都生效了。

第二点,这确实是个问题,要做到针对用户层面的接口限制是必须的,不然有一个用户恶意刷新,其他用户都用不了了,这怎么可以。要解决这个问题,首先要拿到当前操作用的标识,用户名、用户ID,然后再存入key的时候,拼接上这个标识作为key。

	String key = limitAccess.key() + 用户标识(用户名、用户id);

获取当前用户信息,参考下面这篇文章:

  • 获取当前用户信息的几种方式

如果你不是自己从0开发项目,一般成熟的项目都会有获取当前操作用户信息的方式的。实在不行,你让前端把用户id作为参数传给你,你在切面里获取这个用户id都可以。

总结

本文是对之前用Redis接口访问的优化,以及对两个问题的考虑,希望能对大家有启发。

获取源码:https://github.com/HeZhongYing/limit_access_demo

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自动驾驶汽车横向控制方法研究综述

【摘要】 为实现精确、稳定的横向控制,提高车辆自主行驶的安全性和保障乘坐舒适性,综述了近年来自动驾驶汽车横向控制方法的最新进展,包括经典控制方法和基于深度学习的方法,讨论了各类方法的性能特点及在应用中的优缺点&#xff…

【初阶数据结构】详解插入排序 希尔排序(内含排序的概念和意义)

文章目录 前言1. 排序的概念及其应用1.1 排序的概念1.2 排序的应用 2. 插入排序2.1 基本思想2.2 插入排序的代码实现2.3 插入排序算法总结 3. 希尔排序3.1 基本思想3.2 希尔排序的代码实现3.3 希尔排序的特征总结 前言 初级数据结构系列已经进入到了排序的部分了。相信大家听到…

计算机毕业设计 服装生产信息管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…

记录|Modbus-TCP产品使用记录【德克威尔】

目录 前言一、德克威尔1.1 实验图1.2 DECOWELL IO Tester 软件1.3 读写设置1.4 C#进行Modbus-TCP读写 更新时间 前言 参考文章: 使用的第二款Modbus-TCP产品。 一、德克威尔 1.1 实验图 1.2 DECOWELL IO Tester 软件 这也是自带模块配置软件的。下图就是德克威尔的…

“Xian”(籼)和“Geng”(粳)米怎么读?

2018年,《自然》上刊登了一篇有关亚洲栽培稻基因组变异的重磅论文。研究成果本身自然引人关注,但更引人关注的是,这篇论文首次提出以“Xian”(籼)和“Geng”(粳)两个汉语农业术语代替Indica和Ja…

yum使用阿里云的镜像源报错 Failed connect to mirrors.aliyuncs.com:80; Connection refused“

报错:Failed connect to mirrors.aliyuncs.com:80; Connection refused",如果单独只是这个报错的话,那么原因是由于非阿里云ECS用户无法解析主机“mirrors.cloud.aliyuncs.com”。如果不单单只是这个报错另外还有其它报错请参考我其它文…

Threejs创建正多边体

上一章节实现了球体的绘制,这节来绘制多面体,包括正多面体,平面中,每条边一样长组成的图形叫正多边形,这里每个面一样,叫正多面体。如上文一样,先要创建出基础的组件,包括场景&#…

C++基础---类和对象(上)

1.类的定义 C程序设计允许程序员使用类(class)定义特定程序中的数据类型。这些数据类型的实例被称为对象 ,这些实例可以包含程序员定义的成员变量、常量、成员函数,以及重载的运算符。语法上,类似C中结构体&#xff0…

【机器学习】任务六:分类算法(支持向量机(SVM)在线性可分与不可分数据中的应用与可视化分析)

目录 1.知识简介 2.SVM 支持向量机模型训练与可视化报告 2.1 导入本项目所需的模块和包 (1)目的 (2)代码实现 (3)代码解释 2.2 随机生成线性可分的数据并可视化 (1)目的 &a…

[数据集][目标检测]电力场景防震锤缺陷检测数据集VOC+YOLO格式705张1类别

重要说明:防震锤缺陷图片太难找,数据集里面存在大量单一场景图片,请仔细查看图片预览谨慎下载,此外数据集均为小目标检测,如果训练map偏低属于正常现象 数据集格式:Pascal VOC格式YOLO格式(不包含分割路径…

特殊的 BASE64 1

这个一看题目就是base64编码表被改了. 知识点: Base64编码使用一个包含64个字符的字符集,这些字符分别是: 大写字母A-Z小写字母a-z数字0-9特殊字符和/ 这些字符分别对应64个不同的6位二进制数。在补零后形成的8位字节中,实际使用…

c++primier第十二章类和动态内存

本章内容包括: 对类成员使用动态内存分配隐式和显式地复制构造函数隐式和显式地重载赋值操作符在构造函数中使用new所必须完成的工作使用静态类成员 将布局new操作符用于对象使用指向对象的指针实现队列抽象数据类型(ADT) 动态内存和类 复习范例和静态类成员 首…

ASP.NET Zero 多租户介绍

ASP.NET Zero 是一个基于 ASP.NET Core 的应用程序框架,它提供了多租户支持,以下是关于 ASP.NET Zero 多租户的介绍: 一、多租户概念 多租户是一种软件架构模式,允许多个客户(租户)共享同一套软件应用程序…

联邦学习(三只决策和大数据分析)(学习笔记)

联邦学习模型按照数据重叠形式分成了三类,分别是横向联邦学习、纵向联邦学习和联邦迁移学习。 横向联邦学习模型针对特征一致但ID不一致的数据; 纵向联邦学习模型针对ID一致但特征不一致的数据; 联邦迁移学习模型针对ID和特征都不一致的数据。…

Linux网络操作命令与函数全面总结

1. 引言 Linux作为服务器和开发平台,网络操作是其核心功能之一。本文旨在全面总结Linux系统中的网络操作方法,包括命令行工具和编程接口,帮助读者深入理解Linux网络管理的机制。 2. 命令行工具 2.1 ping 命令 ping 命令用于测试网络连接和…

实验OSPF路由协议(课内实验)

实验1:OSPF路由协议 实验目的及要求: 通过实验,能够理解链路状态型路由协议OSPF协议的工作原理,掌握如何实现单区域 OSPFv2配置指令,能够熟练的应用各种OSPF协议相关的配置指令完善网络设计。掌握验证OSPFv2网络连接…

软件开发人员绩效考核方案(参考)

1、产品&运营绩效考核表 2、开发绩效考核表 3、测试绩效考核表 4、CPI指标库 软件全套资料部分文档清单: 工作安排任务书,可行性分析报告,立项申请审批表,产品需求规格说明书,需求调研计划,用户需求调查…

像AI一样思考

我感觉每个人都应该通过Coze平台 https://www.coze.cn/ 创建一个属于自己的Bot。 为什么要创建Bot? 很多时候我们的思维会受各种因素的影响,如感情、知识盲区、心态等,最终导致我们做的决定缺乏逻辑或者考虑不全面。但AI不一样,…

armbian安装docker

最近又搞了台瑞莎Radxa 3E ,从零开始部署unbuntu环境,发现是真曲折啊,虽然有点前车之鉴了 在Armbian上安装Docker,可以按照以下步骤操作: 1、更新软件包列表: sudo apt-get update 2、安装必要的软件包…

leetcode|刷算法 线段树原理以及模板

线段树出现的题目特征 线段树使用的题目。每次操作都要得到返回结果的。 比如 699. 掉落的方块 - 力扣(LeetCode) 2286. 以组为单位订音乐会的门票 - 力扣(LeetCode) 1845. 座位预约管理系统 - 力扣(LeetCode&#…