springBoot防止重复提交

这篇具有很好参考价值的文章主要介绍了springBoot防止重复提交。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

两种方法,
一种是后端实现,较复杂,要通过自定义注解和AOP以及Redis组合实现
另一种是前端实现,简单,只需通过js,设置过期时间,一定时间内,多次点击按钮只生效一次

后端实现

自定义注解+AOP+Redis

自定义注解

package com.wzw.config.anno;

import java.lang.annotation.*;

/**
 * 自定义注解防止表单重复提交
 */
@Target(ElementType.METHOD) // 注解只能用于方法
@Retention(RetentionPolicy.RUNTIME) // 修饰注解的生命周期
@Documented
public @interface RepeatSubmit {

    /**
     * 防重复操作过期时间,默认1s
     */
    long expireTime() default 1;
}

AOP

package com.wzw.config.aspect;

import com.wzw.config.anno.RepeatSubmit;
import com.wzw.config.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
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.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * 防止重复提交切面
 */
@Slf4j
@Component
@Aspect
public class RepeatSubmitAspect {

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 定义切点
     */
    @Pointcut("@annotation(com.wzw.config.anno.RepeatSubmit)")
    public void repeatSubmit() {}

    @Around("repeatSubmit()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        // 获取防重复提交注解
        RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);

        // 获取token当做key
         String token = request.getHeader("token");
        if (StringUtils.isBlank(token)) {
            throw new RuntimeException("token不存在,请登录!");
        }

        String url = request.getRequestURI();
        /**
         *  通过前缀 + url + token 来生成redis上的 key
         *  可以在加上用户id,小编这里没办法获取,大家可以在项目中加上
         */
        String redisKey = "repeat_submit_key:"
                .concat(url)
                .concat(token);
        log.info("==========redisKey ====== {}",redisKey);

        if (!redisTemplate.hasKey(redisKey)) {
            redisTemplate.opsForValue().set(redisKey, redisKey, annotation.expireTime(), TimeUnit.SECONDS);
            try {
                //正常执行方法并返回
                return joinPoint.proceed();
            } catch (Throwable throwable) {
                redisTemplate.delete(redisKey);
                throw new Throwable(throwable);
            }
        } else {
            // 抛出异常
            throw new CustomException("请勿重复提交");
        }
    }
}

自定义异常类和全局异常处理

自定义异常类:CustomException

package com.wzw.config.exception;

/**
 * 自定义异常
 */
public class CustomException extends Exception {

    public CustomException() {
        super();
    }

    public CustomException(String message) {
        super(message);
    }
}

全局异常处理:CustomExceptionHandler

package com.wzw.config.exception;

import com.wzw.base.pojo.Result;
import com.wzw.config.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@RestControllerAdvice
public class CustomExceptionHandler {

    /**
     * 每当抛出CustomException异常,就会进入这里
     * @param e 自定义异常类
     * @return  返回值实体
     */
    @ExceptionHandler(value = CustomException.class)
    @ResponseBody
    public Result handleCustomException(CustomException e){

        Result result=Result.init();
        result.setMsg(e.getMessage());
        result.setCode(0);
        return result;
    }

}


响应实体:Result

package com.wzw.base.pojo;

import lombok.Data;

/**
 * 返回值响应实体
 */
@Data
public class Result {
    private int code;
    private String msg;
    private Object data;

    public static Result init(){
        return new Result();
    }

    public static Result ok(){
        Result result=Result.init();
        result.code=1;
        return result;
    }

    public static Result ok(String msg){
        Result result=Result.ok();
        result.setMsg(msg);
        return result;
    }

    public static Result err(){
        Result result=Result.init();
        result.code=0;
        return result;
    }

    public static Result err(String msg){
        Result result=Result.err();
        result.setMsg(msg);
        return result;
    }
}

Redis

设置Redis配置数据源,然后创建 Redis配置类

package com.wzw.config.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;


@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
    {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);

        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(serializer);

        // Hash的key也采用StringRedisSerializer的序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);

        template.afterPropertiesSet();
        return template;
    }
}

使用

    /**
     * 防止重复提交测试
     * @return  响应实体
     * @throws CustomException  自定义异常类
     */
    @RequestMapping("/testCustomerException")
    @ResponseBody
    @RepeatSubmit(expireTime = 10)  //不加expireTime,默认1s内,加参数可以重新设定防止重复提交的时间
    public Result testCustomerException() throws CustomException {

        Result result=Result.ok("请求成功");

        return result;
    }

可以看到第一次是请求成功,之后五秒都是提示请勿重复提交
springBoot防止重复提交,java

前端实现

来源:https://blog.csdn.net/liangmengbk/article/details/127075604

/* 防止重复点击 */
let clickTimer = 0
 
function clickThrottle() {
  var interval = 3000;//3秒钟之内重复点击只算一次点击
  let now = +new Date(); // 获取当前时间的时间戳
  let timer = clickTimer; // 记录触发事件的事件戳
 
  if (now - timer < interval) {
    // 如果当前时间 - 触发事件时的事件 < interVal,那么不符合条件,直接return false,
    // 不让当前事件继续执行下去
    return false;
  } else {
    // 反之,记录符合条件触发了事件的时间戳,并 return true,使事件继续往下执行
    clickTimer = now;
    return true;
  }
}

在需要的地方进行调用:

if(!clickThrottle()) return;文章来源地址https://www.toymoban.com/news/detail-670034.html

到了这里,关于springBoot防止重复提交的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端如何防止接口重复提交

    接口重复提交指的是在网络通信中,同一个请求被客户端多次发送到服务器端的情况。这种情况可能由于多种原因导致,例如用户在等待期间多次点击提交按钮、网络超时后客户端重新发送请求、客户端发送的请求在网络传输过程中出现重复等。 接口重复提交可能会导致多种

    2024年04月22日
    浏览(35)
  • 微信小程序防止重复提交

    微信小程序在真机测试时,遇到这样一种情况:当网络条件差或卡顿的情况下,进行某项操作时,使用者会认为点击无效而进行多次点击,致使多次跳转页面或多次上传同一表单,导致函数或接口被多次调用,实际上使用者只想调用函数和接口一次。 添加节流阀,即按下按钮

    2024年02月13日
    浏览(49)
  • HTML5中form表单防止重复提交的两种方法

    form表单重复提交是在多用户Web应用中最常见、带来很多麻烦的一个问题。有很多的应用场景都会遇到重复提交问题 (1)点击提交按钮两次。 (2)点击刷新按钮。 (3)使用浏览器后退按钮重复之前的操作 导致重复提交表单。 (4)浏览器重复的HTTP请求。 (5)用户提交表单时可能因为网

    2024年01月22日
    浏览(44)
  • springboot防重复提交

    1、场景 网页卡顿的时候,用户点击会造成重复操作 如果前端不做防重复操作。会导致重复提交,重复下单等意外操作。而且对于系统资源来说也是一种浪费 常规的解决方法是让前端把点击后的按钮设置为不可点击,这样基本上能就能解决了。99.999999%能解决。前端这么弄过

    2024年02月09日
    浏览(29)
  • JAVA -- sm3加密签名,以及防止重复攻击

            后端开发基本都遇到过使用签名校验的情况,签名的作用是为了防止请求数据被别人截取篡改重新请求。         为什么签名验证可以防止请求数据被篡改,因为一般签名的规则就是,你的所有请求参数,按照约定好的格式进行拼接,后面得到一个拼接后的字符串,

    2024年02月12日
    浏览(42)
  • springboot3使用自定义注解+AOP+redis优雅实现防重复提交

      ⛰️个人主页:     蒾酒 🔥 系列专栏 :《spring boot实战》 🌊 山高路远,行路漫漫,终有归途 目录 写在前面 实现思路 实现步骤 1.定义防重复提交注解 2.编写一个切面去发现该注解然后执行防重复提交逻辑 3.测试 依赖条件 1.接口上标记防重复提交注解 2.接口测试 写在最

    2024年04月11日
    浏览(38)
  • springboot实现后端防重复提交(AOP+redis分布式锁)单机情况下

    为什么要实现这个功能呢,可能用户在提交一份数据后,可能因为网络的原因、处理数据的速度慢等原因导致页面没有及时将用户刚提交数据的后台处理结果展示给用户,这时用户可能会进行如下操作: 1秒内连续点击提交按钮,导致重复提交表单。 使用浏览器后退按钮重复之

    2024年02月08日
    浏览(43)
  • SpringBoot自定义注解+AOP+redis实现防接口幂等性重复提交,从概念到实战

    本文为千锋教育技术团独家创作,更多技术类知识干货,点个关注持续追更~ 接口幂等性是Web开发中非常重要的一个概念,它可以保证多次调用同一个接口不会对结果产生影响。如果你想了解更多关于接口幂等性的知识,那么本文就是一个不错的起点。 在Web开发中,我们经常

    2024年02月03日
    浏览(56)
  • Java 解决重复提交问题和表单唯一标识的 Redis 缓存实现

    在开发 Web 应用程序时,重复提交和表单唯一标识是常见的问题。重复提交可能导致数据重复插入或重复操作,而表单唯一标识则用于确保每个表单提交都是唯一的。本文将介绍如何使用 Java 来解决这些问题,并结合 Redis 缓存提供实际的案例。 什么是重复提交问题? 重复提

    2024年02月11日
    浏览(47)
  • 如何防止订单重复支付

    想必大家对在线支付都不陌生,今天和大家聊聊如何防止订单重复支付。 看看订单支付流程 我们来看看,电商订单支付的简要流程: 订单钱包支付流程 从下单/计算开始: 下单/结算 :这一步虽然不是直接的支付起点,但是支付相关的金额等等信息都来自结算,此时订单的

    2024年02月05日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包