后端防止重复点击

请直接看原文:

 后端防止重复点击设计_后端如何防止重复点击-CSDN博客

---------------------------------------------------------------------------------------------------------------------------------

一、背景

    想了解的都懂,不再描述。

二、解决的主要思想

    重复调用会存在在以下几种情况中:

    1、点击一次后无遮罩可进行二次点击。(可通过前端进行设置)

    2、在出现遮罩之前,可能由于屏幕的特殊性,而自行进行了多次点击。(主要是避免此种问题)

    在同一时刻,调用同一个方法,且入参一致则认定为是重复点击,此时不在执行后续方法。

三、思路

    1、为了方法的通用性以及和业务系统进行解耦,在此使用aop的环绕增强。

    2、在增强中判断当前的类名+方法名+入参转换为(json)组装成的key是否已经在redis中存在

(参数里要加上useId)

    3、利用redis的setNx(此方法为原子性,不建议判断后再进行set,避免出现线程安全问题)

    4、返回为true,则说明未提交。调用pjp.proceed方法执行。

        4.1、方法执行后删除当前redis值

    5、返回为false,则说明为重复点击,则直接返回。

四、代码实现

    1、定义注解类

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ForbidRepeatClick { }

    2、定义切面

    @Component
    @Aspect
    @Order(1)
    public class ForbidRepeatClickInterceptor {
        private static final Logger LOGGER = LoggerFactory.getLogger(ForbidRepeatClickInterceptor.class);
        @Pointcut("@annotation(ForbidRepeatClick)")
       public void pointcut() {
       }
        @Around("pointcut()")
        public Object forbidRepeatClick(ProceedingJoinPoint pjp) throws Throwable {
            //1、根据入参方法名获取组装的redis的key值
            String redisKey = getRedisKey(pjp);
            LOGGER.info("ForbidRepeatClickInterceptor->forbidRepeatClick->redisKey:{}", redisKey);
           
            if(RedisUtil.setIfAbsent(redisKey, "exist")) {
                LOGGER.info("ForbidRepeatClickInterceptor->forbidRepeatClick->redisKey:notexist");
                //2、当前方法同一时间段无完全同参数调用,则继续往下执行
               Object res = pjp.proceed();
                //2.1 执行后将数据从redis删除
                RedisUtil.delete(redisKey);
                return res;
            }
        
           //3、当前方法同一时间段具有相同参数执行,则不再执行,直接返回错误标识
           LOGGER.info("ForbidRepeatClickInterceptor->forbidRepeatClick->redisKey:exist");
           CommonResponse commonResponse = new CommonResponse();
           commonResponse.setCode(ResultEnum.REPEAT_CLICK.getNo());
           return commonResponse;      
       }
    
        /**
         * 获取存储的redis的key值
         * @param pjp
         * @return
         */
        private String getRedisKey(ProceedingJoinPoint pjp) {
           
            // 1、获取被代理的对象类型
            String className = pjp.getTarget().getClass().getName();
            
            // 2、获取当前代理的方法名
           String methodName = pjp.getSignature().getName();
           
            // 3、获取入参并转换成jason串
            String convertJson = convertArgsToJson(pjp.getArgs());
           
            String redisKey = className + "->" + methodName + "->" + convertJson;
            
            return redisKey;
        }
    
       /**
         * 将传入的参数拼接成json类型的字符串
         * @param args
         * @return
         */
        private String convertArgsToJson(Object[] args) {
            StringBuilder convertJson = new StringBuilder();
            for (Object object : args) {
               if(!(object instanceof HttpServletRequest)) {  // 此处判断不能舍去
                    convertJson.append(JSON.toJSONString(object));
               }
            }
           return convertJson.toString();
        }

注:本次设计主要是利用到了redis是线程安全的以及redis进行处理分布式问题。

方法返回值的设计在此不再赘述,如果后端方法使用的是同类型的返回值,可直接返回该类型,如果不同类型,请参考策略模式进行设计。

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

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

相关文章

【初始消息队列】消息队列的各种类型

消息队列相关概念 什么是消息队列 MQ(message queue),从字面意思上看,本质是个队列,FIFO 先入先出,只不过队列中存放的内容是 message 而已,还是一种跨进程的通信机制,用于上下游传递消息。在互联网架构中…

【软考高级信息系统项目管理师--第二十章:高级项目管理】

🚀 作者 :“码上有前” 🚀 文章简介 :软考高级–信息系统项目管理师 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 第二十章:高级项目管理 项目集管理项目组合管理组织级项目管理OPM&…

深入探讨Lambda表达式转换为委托类型的编译过程

了解了,如果要深入探讨Lambda表达式转换为委托类型的编译过程,我们需要关注C#编译器如何处理这个转换。这个过程涉及到编译时的类型推断、匿名方法的创建,以及生成对应的委托实例。我们来更详细地分析这个过程: 编译阶段 1. 解…

JVM原理

一、java虚拟机的生命周期: Java虚拟机的生命周期 一个运行中的Java虚拟机有着一个清晰的任务:执行Java程序。程序开始执行时他才运行,程序结束时他就停止。你在同一台机器上运行三个程序,就会有三个运行中的Java虚拟机。 Java虚拟…

Model / View结构

红色部分是可以直接使用的。 QFileSystemModel; QFileSystemModel的使用: 头文件: QFileSystemModel* model nullptr; cpp文件: model new QFileSystemModel; model->setRootPath(QDir::currentPath()); ui->listView->setModel…

纯前端低代码平台demo,vue框架,nodejs,简单的pm2纯前端部署实践

文章目录 目录结构说明本地运行项目启动后的页面demo前端部署打包pm2nginx 后话 前段时间开发了一个纯前端的低代码平台demo,vue框架,nodejs,pm2纯前端部署实践。为此记录一下开发过程以及各方面遇到的问题,并作说明。 表单用了若…

L2-032 彩虹瓶

一、题目 二、解题思路 判断输入的数字(搬来的这箱小球)是否符合:若符合,则 cot (下一个颜色序号);若不符合,则入栈(放到临时货架),如果栈溢出&a…

Java中的线程(创建多线程的三种方法)

Java中的线程——创建 创建多线程方式一:继承Thread类方式二:实现Runnable接口方式三:实现Callable接口 线程的常用API 创建多线程 方式一:继承Thread类 定义一个子类MyThread继承线程类java.lang.Thread,重写run方法…

板块一 Servlet编程:第三节 HttpServletRequest对象全解与请求转发 来自【汤米尼克的JAVAEE全套教程专栏】

板块一 Servlet编程:第三节 HttpServletRequest对象全解与请求转发 一、什么是HttpServletRequest二、接收请求的常用方法三、请求乱码问题四、请求转发:forward五、Request作用域getParameter和getAttribute的区别 在上一节中我们已经学习了完整的Servl…

政安晨:【完全零基础】认知人工智能(一)【超级简单】的【机器学习神经网络】 —— 预测机

开个头 很多小伙伴们很想亲近人工智能与机器学习领域,然而这个领域里的核心理论、算法、工具给人感觉都太过“高冷”,让很多小伙伴们望而却步,导致一直无法入门。 如何捅破这层窗户纸? 让高冷的不再高冷,让神秘的不…

CASS编码对照表

CASS编码对照表,包含了地籍与房产测绘中各种地理信息要素的编码、图层以及对应的名称和描述。这些编码主要应用于地形地貌、水系、居民地、交通设施(如铁路、公路、桥梁、隧道)、地下管线、海岸线、岛屿、矿产资源、建筑物以及其他人工构筑物…

当excel中表格打印预览右边超出限定页面时,调整列宽

解决办法:调整整体列或者部分列的列宽 操作流程如下: 第一步:选中需要调整的列 ①将鼠标放在表格的列上,等出现向下粗箭头后——>②单击(变成粗十字)该列——>③拖动选中列 第二步:调…

30分钟快速上手LaTex

文章目录 30 分钟快速上手 LATEX1.什么是LATEX?2.为什么学习LATEX?3.编写第一个LATEX程序4.LATEX文档的序言5.LATEX文档的标题、作者和日期信息6.LATEX文档的注释7.LATEX文档的粗体、斜体和下划线8.LATEX文档中添加图片9.LATEX中对图像进行标注、标签化和引用10.在LATEX中创建…

【操作系统线程实现方式与多线程模型】

文章目录 操作系统线程实现方式1. 用户级线程(User-Level Threads)2. 内核级线程(Kernel-Level Threads) 多线程模型1. 多对多模型(Many-to-Many Model)2. 一对一模型(One-to-One Model&#xf…

Django后端开发——ORM

文章目录 参考资料ORM-基础字段及选项字段类型练习——添加模型类应用bookstore下的models.py数据库迁移——同步至mysqlmysql中查看效果 字段选项Meta类定义示例:改表名应用bookstore下的models.py终端效果 练习——改表名字段选项修改应用bookstore下的models.py终…

vue3+ts项目搭建

⛰️个人主页: 蒾酒 🔥系列专栏:《vue3实战》 🌊山高路远,行路漫漫,终有归途。 目录 前置条件 基础工程模板搭建 测试环境变量是否配置成功 初始化vue项目 安装常用依赖 基础项目目录介绍 前置条件 请确…

星纪魅族宣布 All in AI;欧盟将首次对苹果处以罚款丨 RTE 开发者日报 Vol.146

开发者朋友们大家好: 这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE (Real Time Engagement) 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

每天分享一个好用的Python库-Colorama

每天分享一个好用的Python库-Colorama 前言 今天分享的是一个主要用来给文本添加各种颜色的库:colorama。 colorama 简介 colorama是一个可以跨多终端显示不同颜色字符与背景的第三方库。 安装 使用pip进行安装 $ pip install colorama简单使用 常用参数 字…

【AIGC】Stable Diffusion应用领域

Stable Diffusion 是一个基于 OpenAI 的 Diffusion 模型的扩展版本,主要用于图像生成和处理任务。它并不是一个图像分类模型,而是一个生成式模型,可以生成高质量的图像。以下是 Stable Diffusion 模型的主要功能和应用领域: 图像…

C语言中关于#include的一些小知识

写代码的过程中,因为手误,重复包含了头文件 可以看到没有报错 如果是你自己编写的头文件,那么如果没加唯一包含标识的话,那么编译器会编译报错的。如果是系统自带的头文件,由于其每个头文件都加了特殊标识&#xff0c…