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

SpringBoot项目防重复提交注解开发

背景

在实际开发过程中,防重复提交的操作很常见。有细分配置针对某一些路径进行拦截,也有基于注解去实现的指定方法拦截的。

分析

实现原理

实现防重复提交,我们很容易想到就是用过滤器或者拦截器来实现。

使用拦截器就是继承HandlerInterceptorAdapter类,实现preHandle()方法;

使用过滤器就是实现OncePerRequestFilter接口,在doFilterInternal()完成对应的防重复提交操作。

OncePerRequestFilter接口详解

在Spring Web应用程序中,过滤器(Filter)也是一种拦截HTTP请求和响应的机制,可以对它们进行处理或修改,从而增强或限制应用程序的功能。OncePerRequestFilter类是Spring提供的一个抽象类,继承自javax.servlet.Filter类,并实现了Spring自己的过滤器接口OncePerRequestFilter,它的目的是确保过滤器只会在每个请求中被执行一次,从而避免重复执行过滤器逻辑所带来的问题,如重复添加响应头信息等。

OncePerRequestFilter类中有一个doFilterInternal()方法,用于实现过滤器的逻辑,该方法只会在第一次请求时被调用,之后不再执行,确保了过滤器只会在每个请求中被执行一次。

实际场景考虑

使用过滤器的话,会对所有的请求都进行防重复提交。但对于一些查询接口来说,并不需要防重复提交。那么怎样在指定的接口需要使用防重复提交拦截呢?答案就是用注解

实现步骤

1.定义注解@DuplicateSubmission

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 DuplicateSubmission {
}

2.DuplicateSubmissionFilter 实现防重复提交

方法一:基于过滤器与session

public class DuplicateSubmissionFilter extends OncePerRequestFilter {private final Logger LOGGER = LoggerFactory.getLogger(DuplicateSubmissionFilter.class);@Value("app.duplicateSubmission.time")/** 两次访问间隔时间 单位:毫秒 */private long intervalTime;@Autowiredprivate HttpSession session;@Autowiredprivate HandlerMapping handlerMapping;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {HandlerMethod handlerMethod = getHandlerMethod(request);if (handlerMethod != null && handlerMethod.getMethodAnnotation(DuplicateSubmission.class) != null) {// 这里的token不一定是要用户标识,如果是设备之类也行,能有唯一性就好String token = request.getHeader("token");// 这里存到session中,也可以用redis改造if (token == null) {LOGGER.warn("token为空!");}String key = token + request.getRequestURI();long nowTime = System.currentTimeMillis();Object sessionObj = session.getAttribute(key);if (sessionObj != null) {long lastTime = (long) sessionObj;session.setAttribute(key, nowTime);// 两次访问的时间小于规定的间隔时间if (intervalTime > (nowTime - lastTime)) {LOGGER.warn("重复提交!");return;}}}filterChain.doFilter(request, response);}private HandlerMethod getHandlerMethod(HttpServletRequest request) throws NoSuchMethodException {HandlerExecutionChain handlerChain = null;try {handlerChain = handlerMapping.getHandler(request);} catch (Exception e) {LOGGER.error("Failed to get HandlerExecutionChain.", e);}if (handlerChain == null) {return null;}Object handler = handlerChain.getHandler();if (!(handler instanceof HandlerMethod)) {return null;}return (HandlerMethod) handler;}
}

但其实这个方案还需要考虑一个场景:如果设置的防重复提交时间间隔小,用户体验不会有什么奇怪。如果设置了1分钟以上,那我们要考虑完善这个方案,防重复提交还有一个重要的判断依据,就是参数相同。**当时间小于间隔时间,且参数相同时,认定为重复提交。**这一步也没什么复杂,就只是建一个map,把请求时间和参数放进map,再保存到 session中。

方式二

基于拦截器与redis实现,使用拦截器记得要在你的WebMvcConfigurer实现类上注册!

@Component
@Slf4j
public class DuplicateSubmissionInterceptor implements HandlerInterceptor {@Value("app.duplicateSubmission.time")/** 两次访问间隔时间 单位:毫秒 */private long intervalTime;@Autowiredprivate StringRedisTemplate redisTemplate;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();DuplicateSubmission annotation = method.getAnnotation(DuplicateSubmission.class);// 使用了注解if (annotation != null) {// 获取key值String key = token + request.getRequestURI();// 直接用redis的setIfAbsentboolean firstRequest = redisTemplate.opsForValue().setIfAbsent(key, "flag", intervalTime, TimeUnit.SECONDS);// 如果设置不成功,那就是重复提交if (!firstRequest) {log.warn("重复提交");// 通常来说这里还有抛个全局处理异常return;}}}return true;}}

同样的,如果设置的重复提交过长,则需要把请求参数放到redis的value值中(上面只是用了"flag"作为一个假的值),对比请求参数是否一致。

使用方式

使用方法很简单,只需要在需要进行防重复提交的方法上加上一个注解即可

@PostMapping("/submit")
@DuplicateSubmission
public String submitForm() {// 处理表单提交请求// ...return "result";
}

相关文章:

SpringBoot项目防重复提交注解开发

背景 在实际开发过程中,防重复提交的操作很常见。有细分配置针对某一些路径进行拦截,也有基于注解去实现的指定方法拦截的。 分析 实现原理 实现防重复提交,我们很容易想到就是用过滤器或者拦截器来实现。 使用拦截器就是继承HandlerInt…...

从软件哲学角度谈 Amazon SageMaker

如果你喜欢哲学并且你是一个 IT 从业者,那么你很可能对软件哲学感兴趣,你能发现存在于软件领域的哲学之美。本文我们就从软件哲学的角度来了解一下亚马逊云科技的拳头级产品 Amazon SageMaker,有两个出发点:一是 SageMaker 本身设…...

C++内联函数

目录 一、常规函数和内联函数的对比 二、如何使用 三、内联函数的特性 四、内联函数与宏 五、如何查看内联函数 六、【面试题】 前言-----内联函数是C中为程序运行速度所做的一项该进。常规函数和内联函数之间的主要区别不在于编写方式,而在于C编译器如何将他…...

JAVA大师的秘籍:轻松掌握高质量代码之道

如果你想写出高质量的代码,那掌握编写技巧可是必不可少哦!这不仅能让你的代码变得更加易读易维护,还可以让你的应用程序性能更强、稳定性更高!所以,别怕麻烦,多花些时间和心思在代码上,相信你一定能成为优秀的JAVA开发者! 要想让代码易读易维护、性能稳定,得拿出耐心和…...

OpenGL入门教程之 变换

引言 这是一个闪耀的时刻,因为我们即将能生产出令人惊叹的3D效果! 变换 向量和矩阵变换包括太多内容,但由于学过线性代数和GAMES101,因此不在此做过多阐述。仅阐述包括代码的GLM内容。 GLM的使用 (1)GLM…...

ASPICE详细介绍-4.车载项目为什么要符合ASPICE标准?

目录 车载项目为什么要符合ASPICE标准?ASPICE与功能安全的关系、区别?各大车厂对软件体系的要求 车载项目为什么要符合ASPICE标准? ASPICE(Automotive Software Process Improvement and Capability Determination)最…...

一文彻底理解Java 17中的新特性密封类

密封类的作用 在面向对象语言中,我们可以通过继承(extend)来实现类的能力复用、扩展与增强。但有的时候,有些能力我们不希望被继承了去做一些不可预知的扩展。所以,我们需要对继承关系有一些限制的控制手段。而密封类…...

【Git 入门教程】第四节、Git冲突:如何解决版本控制的矛盾

Git是目前最流行的版本控制系统之一,它为团队协作开发提供了方便和高效的方式。然而,在多人同时修改同一个文件时,可能会出现代码冲突(conflict),导致代码无法正确合并。那么,如何解决Git冲突呢…...

c++验证用户输入合法性的示例代码

c验证用户输入合法性的示例代码 本文介绍c验证用户输入合法性,用于检测限定用户输入值。包括:1、限定用户输入为整数(正负整数);2、限定用户输入为正整数;3、限定用户输入为正数(可以含有小数&…...

ctfshow web入门phpcve web311-315

1.web311 通过抓包发现php版本时为PHP/7.1.33dev 漏洞cve2019-11043 远程代码执行漏洞 利用条件: nginx配置了fastcgi_split_path_info 受影响系统: PHP 5.6-7.x,Nginx>0.7.31 下载工具进行利用 需要安装go环境 yum install golang -y …...

gpt.4.0-gpt 国内版

gpt 使用 GPT(Generative Pre-trained Transformer)是一种预训练的语言模型,可用于多种自然语言处理任务,如情感分析、文本分类、文本生成等。下面是使用GPT的一些步骤和建议: 确定任务和数据集:首先&…...

放弃手动测试,快来了解JMeter压测神器的安装和使用吧~~

目录:导读 引言 jmeter的安装 JMeter是干什么的 JMeter都可以做那些测试 JMeter的使用和组件介绍 下面我们进行XML格式的实战练习 jmeter与postman的区别 JSON的插件 另附视频教程资源 引言 你是否曾经为手动测试而苦恼?是不是觉得手动测试太费…...

SQL函数

文章目录 一、SQL 函数二、SQL COUNT() 函数三、SQL FIRST() 函数四、SQL LAST() 函数五、SQL MAX() 函数总结 一、SQL 函数 SQL 拥有很多可用于计数和计算的内建函数。 SQL Aggregate 函数 SQL Aggregate 函数计算从列中取得的值,返回一个单一的值。 有用的 Aggre…...

苦熬10年,国产操作系统“归零”,新操作系统上新,跟Excel很像

苦熬10余年,国产操作系统自主研发 说到国内自主研发的操作系统,经验最丰富的品牌,当然是麒麟OS. 从诞生到发展,历经10多年的努力,麒麟os逐渐成为了国内自主研发操作系统领域中的一颗耀眼的明珠。麒麟OS不仅推出了许多…...

什么是shell脚本和简单shell脚本练习

文章目录 什么是shell脚本和简单shell脚本练习什么是shell脚本为什么要学习shell脚本第一个脚本编写与执行编写第一个脚本 简单的shell脚本练习简单案例交互式脚本:变量内容由用户决定随日期变化:利用date建立文件数值运算:简单的加减乘除数值…...

MySQL MyBatis

MySQL从表中随机查一条数据 SELECT * FROM address ORDER BY RAND() LIMIT 1MySQL查询表是否存在 select count(*) from information_schema.TABLES where table_name #{tableName}插入数据插入随机的uuid <insert id"insertComment" parameterType"com.…...

Leetcode力扣秋招刷题路-0802

从0开始的秋招刷题路&#xff0c;记录下所刷每道题的题解&#xff0c;帮助自己回顾总结 802. 找到最终的安全状态 有一个有 n 个节点的有向图&#xff0c;节点按 0 到 n - 1 编号。图由一个 索引从 0 开始 的 2D 整数数组 graph表示&#xff0c; graph[i]是与节点 i 相邻的节…...

编程中最难的就是命名?这几招教你快速上手

作者&#xff1a;陈立(勤仁) 你可不能像给狗狗取名字那样给类、方法、变量命名。仅仅因为它很可爱或者听上去不错。 在写代码的时候&#xff0c;你要经常想着&#xff0c;那个最终维护你代码的人可能将是一个有暴力倾向的疯子&#xff0c;并且他还知道你住在哪里。 01 为什么…...

NUXT规范及常见问题

props中不要使用Web环境才有的对象&#xff0c;服务端渲染的时候会失败 使用<Nuxt/>组件代替<router-view/>&#xff0c;使用<NuxtLink/>代替<router-link/>static目录下的资源是静态资源&#xff0c;不应该通过import或../static/img/logo.png等方式…...

2023年Q1天猫空调品牌销量排行榜

如今&#xff0c;空调的普及水平较高&#xff0c;空调行业进入存量换新为主的发展阶段。 根据鲸参谋数据分析平台的相关数据显示&#xff0c;2023年Q1在天猫平台上&#xff0c;空调的销量将近100万件&#xff0c;销售额将近30亿&#xff0c;同时&#xff0c;空调产品的产品均价…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...