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.mzph.cn/bicheng/61128.shtml

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

相关文章

Linux性能优化之火焰图简介

Linux 火焰图&#xff08;Flame Graph&#xff09;是一种可视化工具&#xff0c;用于分析程序性能问题&#xff0c;尤其是 CPU 使用情况。它展示了程序中函数调用的层次结构和各个调用栈占用的时间比例。 以下是详细介绍&#xff0c;包括火焰图的工作原理、生成步骤和实际使用中…

笔记|M芯片MAC (arm64) docker上使用 export / import / commit 构建amd64镜像

很简单的起因&#xff0c;我的东西最终需要跑在amd64上&#xff0c;但是因为mac的架构师arm64&#xff0c;所以直接构建好的代码是没办法跨平台运行的。直接在arm64上pull下来的docker镜像也都是arm64架构。 检查镜像架构&#xff1a; docker inspect 8135f475e221 | grep Arc…

【JavaWeb】JavaWeb入门之XML详解

目录 1.XML介绍 1.1.XML概述 1.1.1.什么是XML 1.1.2.XML的作用 1.1.3.XML与HTML的比较 1.1.4.XML和properties&#xff08;属性文件&#xff09;比较 1.1.5.W3C组织 1.2.XML语法概述 1.2.1.XML文档展示 1.2.2.XML文档的组成部分 1.3.XML文档声明 1.3.1.什么是XML文…

spring源码02-spring容器启动(容器初始化+bean实例化)源码解读【常见面试题】

文章目录 【README】【1】spring容器初始化及bean实例化步骤列表【2】spring容器初始化源码【2.1】容器初始化主要步骤总结&#xff1a;【2.2】容器初始化详细步骤源码分析 【3】bean实例化源码【3.1】bean实例化主要步骤总结&#xff08;非常重要&#xff09;【3.1.1】 bean生…

Python中的正则表达式教程

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

【Python库安装】Python环境安装景观模式分析常用库PyLandStats

【Python库安装】Python环境安装景观模式分析常用库PyLandStats PyLandStats 简介景观分割景观指标 PyLandStats 安装参考 PyLandStats 简介 PyLandStats 是一个用于景观模式分析的 Python 库。它允许用户计算景观格局的各种统计量和指标&#xff0c;广泛应用于生态学、地理信…

Visual Studio 2022 安装

下载链接 https://visualstudio.microsoft.com/zh-hans/thank-you-downloading-visual-studio/?skuCommunity&channelRelease&versionVS2022&sourceVSLandingPage&cid2030&passivefalse 安装 以c为例&#xff0c;列出需要勾选的项目&#xff0c;有3个&a…

Spark 共享变量:广播变量与累加器解析

Spark 的介绍与搭建&#xff1a;从理论到实践_spark环境搭建-CSDN博客 Spark 的Standalone集群环境安装与测试-CSDN博客 PySpark 本地开发环境搭建与实践-CSDN博客 Spark 程序开发与提交&#xff1a;本地与集群模式全解析-CSDN博客 Spark on YARN&#xff1a;Spark集群模式…

Golang | Leetcode Golang题解之第565题数组嵌套

题目&#xff1a; 题解&#xff1a; func arrayNesting(nums []int) (ans int) {n : len(nums)for i : range nums {cnt : 0for nums[i] < n {i, nums[i] nums[i], ncnt}if cnt > ans {ans cnt}}return }

Git 搭建远程仓库、在 IDEA 工具中的配置和使用

Git的概念、安装、操作与分支管理和图形化界面TortoiseGit&#xff08;小乌龟 &#xff09;的安装与使用-CSDN博客 目录 一、远程仓库 1&#xff09;在github上创建仓库 2&#xff09;在gitee上创建项目 3&#xff09;如何将远程的项目clone 到本地 4&#xff09;公司自己…

无人机检测车辆——多目标检测

目录 YOLOv3&#xff08;You Only Look Once version 3&#xff09;简介 YOLOv3 的主要特点 YOLOv3 的结构 1. 特征提取网络&#xff08;Backbone&#xff09; 2. 检测头&#xff08;Head&#xff09; 3. 输出层 YOLOv3 损失函数 YOLOv3 的优势 YOLOv3 的应用 YOLOv3…

Java | Leetcode Java题解之第564题寻找最近的回文数

题目&#xff1a; 题解&#xff1a; class Solution {public String nearestPalindromic(String n) {long selfNumber Long.parseLong(n), ans -1;List<Long> candidates getCandidates(n);for (long candidate : candidates) {if (candidate ! selfNumber) {if (ans…

字节青训-小C的外卖超时判断、小C的排列询问

目录 一、小C的外卖超时判断 问题描述 测试样例 解题思路&#xff1a; 问题理解 数据结构选择 算法步骤 最终代码&#xff1a; 运行结果&#xff1a; 二、小C的排列询问 问题描述 测试样例 最终代码&#xff1a; 运行结果&#xff1a; ​编辑 一、小C的外卖超时判断…

linux使用scp和密钥在不同服务器传输文件

将源服务密钥中公钥&#xff08;以pub结尾的&#xff09;复制或拷贝密文&#xff0c;粘贴到目标服务器中的/root/.ssh/authorized_keys文件中&#xff1b; 测试连接&#xff1a;ssh -p2129 root172.129.162.537&#xff0c;如果使用默认端口22 -p参数可省略&#xff0c;注意这…

数据结构习题——有效的括号(栈),栈与队列和互相实现,循环队列的实现

文章目录 前言1、有效的括号题目思路代码 2、用队列实现栈题目思路代码 3、用栈实现对列题目思路代码 4、设计循环队列4.1循环队列的概念和了解题目思路代码 总结 前言 继上篇博客学习了栈与队列之后&#xff0c;今天我们来尝试着使用他们来写一些题目&#xff0c;话不多说&…

常用命令之LinuxOracleHivePython

1. 用户改密 passwd app_adm chage -l app_adm passwd -x 90 app_adm -> 执行操作后&#xff0c;app_adm用户的密码时间改为90天有效期--查看该euser用户过期信息使用chage命令 --chage的参数包括 ---m 密码可更改的最小天数。为零时代表任何时候都可以更改密码。 ---M 密码…

IDEA优雅debug

目录 引言一、断点分类&#x1f384;1.1 行断点1.2 方法断点1.3 属性断点1.4 异常断点1.5 条件断点1.6 源断点1.7 多线程断点1.8 Stream断点 二、调试动作✨三、Debug高级技巧&#x1f389;3.1 watch3.2 设置变量3.3 异常抛出3.4 监控JVM堆大小3.5 数组过滤和筛选 引言 使用ID…

鸿蒙学习生态应用开发能力全景图-赋能套件(1)

文章目录 赋能套件鸿蒙生态应用开发能力全景图 赋能套件 鸿蒙生态白皮书: 全面阐释了鸿蒙生态下应用开发核心理念、关键能力以及创新体验,旨在帮助开发者快速、准确、全面的了解鸿蒙开发套件给开发者提供的能力全景和未来的愿景。 视频课程: 基于真实的开发场景,提供向导式…

贴代码框架PasteForm特性介绍之select,selects,lselect和reload

简介 PasteForm是贴代码推出的 “新一代CRUD” &#xff0c;基于ABPvNext&#xff0c;目的是通过对Dto的特性的标注&#xff0c;从而实现管理端的统一UI&#xff0c;借助于配套的PasteBuilder代码生成器&#xff0c;你可以快速的为自己的项目构建后台管理端&#xff01;目前管…

人工智能技术的应用前景与我们的应对策略

​ 大家好&#xff0c;我是程序员小羊&#xff01; 随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;其在社会生活、产业转型以及科技进步中发挥着日益重要的作用。AI正逐步改变着我们的生活和工作方式&#xff0c;同时也带来了技术和伦理上的诸多挑战。本文…