Spring Boot 接口防重复提交解决方案

文章目录

    • 前言
    • 使用Token机制
      • 实现步骤
        • 1.生成Token
        • 2.传递Token
        • 3.验证Token
    • 使用Redis
      • 实现步骤
        • 1.引入Redis依赖
        • 2.生成Token
        • 3.传递Token
        • 4.验证Token
    • 使用Spring AOP
      • 实现步骤
        • 1.定义注解
        • 2.创建切面
        • 3.使用注解
    • 总结

前言

在Web开发中,防止用户重复提交表单是一个常见的需求。用户可能会因为网络延迟、误操作等原因多次点击提交按钮,导致后台接收到多个相同的请求。这不仅会浪费服务器资源,还可能导致数据不一致等问题。本文将介绍几种在Spring Boot中实现接口防重复提交的方法。
在这里插入图片描述

使用Token机制

Token机制是一种常见的防重复提交方法。具体步骤如下:
生成Token:用户每次请求表单页面时,服务器生成一个唯一的Token,并将其存储在Session中。
传递Token:将Token嵌入到表单中,随表单一起提交。
验证Token:服务器接收到请求后,首先验证Token是否有效,如果有效则继续处理请求,并从Session中移除该Token;如果无效,则返回错误信息。

实现步骤

1.生成Token

在Controller中生成Token并存储在Session中:

/*** form* @param session* @author senfel* @date 2024/11/12 11:29* @return org.springframework.web.servlet.ModelAndView*/
@GetMapping("/form")
public ModelAndView showForm(HttpSession session) {ModelAndView form = new ModelAndView("form");String token = UUID.randomUUID().toString();session.setAttribute("token", token);form.addObject("token", token);return form;
}
2.传递Token

在表单中添加隐藏字段来传递Token:

<form action="/base/submit" method="post"><input type="hidden" name="token" th:value="${token}"><!-- 其他表单字段 --><button type="submit">Submit</button>
</form>
3.验证Token

在Controller中验证Token:

/*** handleForm* @param token* @param session* @author senfel* @date 2024/11/12 11:34* @return java.lang.String*/
@PostMapping("/submit")
public String handleForm(@RequestParam String token, HttpSession session) {String sessionToken = (String) session.getAttribute("token");if (sessionToken == null || !sessionToken.equals(token)) {throw new RuntimeException("Duplicate submit detected");}// 移除Tokensession.removeAttribute("token");// 处理表单数据return "success";
}

使用Redis

Redis是一个高性能的键值存储系统,可以用来存储和验证Token。具体步骤如下:
生成Token:用户每次请求表单页面时,服务器生成一个唯一的Token,并将其存储在Redis中。
传递Token:将Token嵌入到表单中,随表单一起提交。
验证Token:服务器接收到请求后,首先验证Token是否存在于Redis中,如果存在则继续处理请求,并从Redis中删除该Token;如果不存在,则返回错误信息。

实现步骤

1.引入Redis依赖

在 pom.xml 中添加Redis依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.生成Token

在Controller中生成Token并存储在Redis中:

@Autowired
private StringRedisTemplate redisTemplate;/*** formByRedis* @author senfel* @date 2024/11/12 11:50* @return org.springframework.web.servlet.ModelAndView*/
@GetMapping("/formByRedis")
public ModelAndView showFormByRedis() {ModelAndView form = new ModelAndView("form");String token = UUID.randomUUID().toString();// 设置过期时间redisTemplate.opsForValue().set(token, token, 5, TimeUnit.MINUTES);form.addObject("token", token);return form;
}
3.传递Token

在表单中添加隐藏字段来传递Token:

<form action="/base/submitByRedis" method="post"><input type="hidden" name="token" th:value="${token}"><!-- 其他表单字段 --><button type="submit">Submit</button>
</form>
4.验证Token

在Controller中验证Token:

/*** submitByRedis* @param token* @author senfel* @date 2024/11/12 11:50* @return java.lang.String*/
@PostMapping("/submitByRedis")
public String handleFormByRedis(@RequestParam String token) {String redisToken = redisTemplate.opsForValue().get(token);if (redisToken == null) {throw new RuntimeException("Duplicate submit detected");}// 删除TokenredisTemplate.delete(token);// 处理表单数据return "success";
}

使用Spring AOP

Spring AOP(Aspect-Oriented Programming)可以用来实现切面编程,从而在多个方法中复用防重复提交的逻辑。

实现步骤

1.定义注解

创建一个自定义注解 @PreventDuplicateSubmit:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** PreventDuplicateSubmit* @author senfel* @date 2024/11/12 11:56*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PreventDuplicateSubmit {/**重复请求时间*/int expireSeconds() default 10;
}
2.创建切面

创建一个切面类 DuplicateSubmitAspect:

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;/*** DuplicateSubmitAspect* @author senfel* @version 1.0* @date 2024/11/12 11:57*/
@Slf4j
@Aspect
@Component
public class DuplicateSubmitAspect {protected static final Logger logger = LoggerFactory.getLogger(DuplicateSubmitAspect.class);@Autowiredprivate StringRedisTemplate redisTemplate;/*** around* @param joinPoint* @author senfel* @date 2024/11/12 15:45* @return java.lang.Object*/@Around("@annotation(com.example.ccedemo.aop.PreventDuplicateSubmit)")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {StringBuilder key = new StringBuilder();//获取classString simpleName = joinPoint.getTarget().getClass().getSimpleName();key.append(simpleName);// 获取请求方法MethodSignature signature=(MethodSignature)joinPoint.getSignature();Method method = signature.getMethod();String methodName = method.getName();key.append(":").append(methodName);//获取请求参数Object[] args=joinPoint.getArgs();for (Object arg : args) {key.append(":").append(arg.toString());}//TODO 获取客户端IP// 获取注解信息PreventDuplicateSubmit annotation = method.getAnnotation(PreventDuplicateSubmit.class);// 判断是否已经请求过if(redisTemplate.hasKey(key.toString())){throw new RuntimeException("请勿重复提交");}//标记请求已经处理过redisTemplate.opsForValue().set(key.toString(),"1",annotation.expireSeconds(), TimeUnit.SECONDS);return joinPoint.proceed();}
}
3.使用注解

在Controller方法上使用 @PreventDuplicateSubmit 注解:

/*** handleFormByAnnotation* @param param* @author senfel* @date 2024/11/12 11:59* @return java.lang.String*/
@PostMapping("/submitByAnnotation")
@PreventDuplicateSubmit
public String handleFormByAnnotation(@RequestParam String param) {// 处理表单数据return "success";
}

总结

本文介绍了三种在Spring Boot中实现接口防重复提交的方法:使用Token机制、使用Redis和使用Spring AOP。每种方法都有其适用场景和优缺点,可以根据实际需求选择合适的方法。通过这些方法,可以有效防止用户重复提交表单,提高系统的稳定性和用户体验。

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

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

相关文章

【QT】解决生成的exe文件出现“无法定位程序入口”或“找不到xxx.dll”的问题

【QT】解决生成的exe文件出现“无法定位程序入口”或“找不到xxx.dll”的问题 零、问题 使用QT编译好项目后&#xff0c;想直接在文件资源管理器中运行exe程序或想分享出去给别人使用发现出现如下问题&#xff1a; 系统错误&#xff1a;找不到xxx.dll。 无法找到入口&#x…

Tomcat启动过程中cmd窗口(控制台)中文乱码的问题

目录 一、问题产生 二、问题分析 三、解决方法(2种) 一、问题产生 在服务器上使用新的Tomcat9(绿色版ZIP),打开一个cmd窗口后,将路径定位到“tomcat\bin\”目录,运行“startup.bat”。程序会自动打开一个新窗口,这个是Java程序的运行窗口,但是里面的中文全是乱码,如…

【MySQL】MySQL数据库入门:构建你的数据基石

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;MySQL初阶探索&#xff1a;构建数据库基础 欢迎大家点赞收藏评论&#x1f60a; 目录 &#x1f985;数据库基础&#x1f400;什么是数据库&#x1f40f;主流数据库&#x1f986;MySQL数据库的基本…

如何使用正则表达式验证域名

下面是一篇关于如何使用正则表达式验证域名的教程。 如何使用正则表达式验证域名 简介 域名是互联网上网站的地址&#xff0c;每个域名由多个标签&#xff08;label&#xff09;组成&#xff0c;标签之间用点 . 分隔。域名规则有很多细节&#xff0c;但基本要求是&#xff1a…

Python中的正则表达式教程

一、 正则表达式基础 1。1。概念介绍 正则表达式是用于处理字符串的强大工具,它并不是Python的一部分。 其他编程语言中也有正则表达式的概念,区别只在于不同的编程语言实现支持的语法数量不同。 它拥有自己独特的语法以及一个独立的处理引擎&#xff0c;在提供了正则表达式…

2024 同一个网段,反弹shell四种方法【linux版本】bash、python、nc、villian反弹shell图解步骤

实验环境准备&#xff08;同一个网段下&#xff0c;我是桥接的虚拟机&#xff09; 一、bash反弹shell 二、python反弹shell 三、nc反弹shell 四、villain反弹shell 实验环境准备&#xff08;同一个网段下&#xff0c;我是桥接的虚拟机&#xff09; 一台kali的linux(攻击者)…

Nginx server_name配置错误导致路由upstream超时问题

一、问题描述 某次本平台和外部平台接口调用&#xff0c;同样Nginx location配置&#xff0c;测试环境调用正常&#xff0c;生产环境调用返回失败&#xff1b; 相关链接&#xff1a;Nginx官方文档、server_name、How nginx processes a request 二、排查处理 1&#xff09…

6.584-Lab1:MapReduce

前置知识/概念 Raft 是一个基于“Leader”的协议&#xff0c;能够保证分布式网路的一致性。 RPC&#xff08;Remote Producer Call&#xff09; 参考链接1 参考链接2 Go中RPC的简单实现 Golang中regexp正则表达式的用法 https://gukaifeng.cn/posts/golang-zheng-ze-biao-…

脑机接口、嵌入式 AI 、工业级 MR、空间视频和下一代 XR 浏览器丨RTE2024 空间计算和新硬件专场回顾

这一轮硬件创新由 AI 引爆&#xff0c;或许最大受益者仍是 AI&#xff0c;因为只有硬件才能为 AI 直接获取最真实世界的数据。 在人工智能与硬件融合的新时代&#xff0c;实时互动技术正迎来前所未有的创新浪潮。从嵌入式系统到混合现实&#xff0c;从空间视频到脑机接口&…

Restful API接⼝简介及为什么要进⾏接⼝压测

一、RESTful API简介 在现代Web开发中&#xff0c;RESTful API已经成为一种标准的设计模式&#xff0c;用于构建和交互网络应用程序。本文将详细介绍RESTful API的基本概念、特点以及如何使用它来设计高效的API接口。 1. 基于协议 HTTP 或 HTTPS RESTful API通常使用HTTP&am…

面试经典 150 题:20、2、228、122

20. 有效的括号 参考代码 #include <stack>class Solution { public:bool isValid(string s) {if(s.size() < 2){ //特判&#xff1a;空字符串和一个字符的情况return false;}bool flag true;stack<char> st; //栈for(int i0; i<s.size(); i){if(s[i] ( |…

Python爬虫下载新闻,Flask展现新闻(2)

上篇讲了用Python从新闻网站上下载新闻&#xff0c;本篇讲用Flask展现新闻。关于Flask安装网上好多教程&#xff0c;不赘述。下面主要讲 HTML-Flask-数据 的关系。 简洁版 如图&#xff0c;页面简单&#xff0c;主要显示新闻标题。 分页&#xff0c;使用最简单的分页技术&…

基于Java和Vue实现的上门做饭系统上门做饭软件厨师上门app

市场前景 生活节奏加快&#xff1a;在当今快节奏的社会中&#xff0c;越来越多的人因工作忙碌、时间紧张而无法亲自下厨&#xff0c;上门做饭服务恰好满足了这部分人群的需求&#xff0c;为他们提供了便捷、高效的餐饮解决方案。个性化需求增加&#xff1a;随着人们生活水平的…

【配置后的基本使用】CMake基础知识

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;各种软件安装与配置_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1.…

Centos 7 安装wget

Centos 7 安装wget 最小化安装Centos 7 的话需要上传wget rpm包之后再路径下安装一下。rpm包下载地址&#xff08;http://mirrors.163.com/centos/7/os/x86_64/Packages/&#xff09; 1、使用X-ftp 或者WinSCP等可以连接上传的软件都可以首先连接服务器&#xff0c;这里我用的…

Linux最深刻理解页表于物理内存

目录 物理内存管理 页表设计 物理内存管理 如果磁盘上的内容加载到物理内存上&#xff0c;每次io都会按照4kb的方式进行加载(可能不同版本系统有些区别)。所以我们的物理内存上的内容也是4个字节进行管理的。 而每个页框都需要我们进行管理。所以自然物理内存就会对页框进行先…

几何合理的分片段感知的3D分子生成 FragGen - 评测

FragGen 来源于 2024 年 3 月 25 日 预印本的文章&#xff0c;文章题目是 Deep Geometry Handling and Fragment-wise Molecular 3D Graph Generation&#xff0c; 作者是 Odin Zhang&#xff0c;侯廷军&#xff0c;浙江大学药学院。FragGen 是一个基于分子片段的 3D 分子生成模…

PySpark——Python与大数据

一、Spark 与 PySpark Apache Spark 是用于大规模数据&#xff08; large-scala data &#xff09;处理的统一&#xff08; unified &#xff09;分析引擎。简单来说&#xff0c; Spark 是一款分布式的计算框架&#xff0c;用于调度成百上千的服务器集群&#xff0c;计算 TB 、…

基于Java Springboot编程语言在线学习平台

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…

WebRTC视频 02 - 视频采集类 VideoCaptureModule

WebRTC视频 01 - 视频采集整体架构 WebRTC视频 02 - 视频采集类 VideoCaptureModule&#xff08;本文&#xff09; WebRTC视频 03 - 视频采集类 VideoCaptureDS 上篇 WebRTC视频 04 - 视频采集类 VideoCaptureDS 中篇 WebRTC视频 05 - 视频采集类 VideoCaptureDS 下篇 一、前言…