首页 > 其他分享 >springboot防重复提交

springboot防重复提交

时间:2023-06-16 14:36:38浏览次数:36  
标签:key springboot 重复 token 提交 ElementType String

springboot防重复提交

1、场景

网页卡顿的时候,用户点击会造成重复操作

如果前端不做防重复操作。会导致重复提交,重复下单等意外操作。而且对于系统资源来说也是一种浪费

常规的解决方法是让前端把点击后的按钮设置为不可点击,这样基本上能就能解决了。99.999999%能解决。前端这么弄过后,就没有遇到过需要后端弄的了。

为了万无一失,剩下的不能解决的就需要后端做防重复点击的操作了。

2、解决方案

2.1、前端通过js让按钮点击后失效,基本上就够了。除非别人要搞你网站,直接扒你接口,放心,你的网站没有那么有价值。

2.2、数据库增加唯一索引,不建议改数据库,虽然方便。

2.3、利用令牌防止表单重复提交

表单页面初始化时,会从后端获取一个生成一个token,这个token放在表单隐藏,当表单提交时一起提交,提交后后端使该token失效;

后端判断前端提交的token为空或者失效则表单提交失败(发送token,验证token)这里需要前后端配合

2.4、使用Spring AOP自定义切入实现,作为后端,倾向于这种方式。

一般接口提交时会有token验证,表明该请求是合法一个用户。后端可以通过 用户token+类+方法来判断是否是重复请求。

RepeatSubmitTestController 文件

@RestController
@RequestMapping(path = "/repeatSubmitTest", produces = "application/json;charset=UTF-8")
public class RepeatSubmitTestController{

    @GetMapping("/listPage")
    @RepeatSubmit(timeout = 20000)
    @ApiOperation(value = "条件查询列表分页", notes = "条件查询列表分页")
    public ResponseBean listPage(@RequestParam Map<String, Object> params, HttpServletRequest request) throws MyException {
        return new ResponseBean(Constants.CODE_SUCCESS, "操作成功", "");
    }

}

RepeatSubmit 文件

// @Target 表示该注解用于什么地方
//        ElementType.CONSTRUCTOR 用在构造器
//        ElementType.FIELD 用于描述域-属性上
//        ElementType.METHOD 用在方法上
//        ElementType.TYPE 用在类或接口上
//        ElementType.PACKAGE 用于描述包
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE})

//@Retention 表示在什么级别保存该注解信息
//        RetentionPolicy.SOURCE 保留到源码上
//        RetentionPolicy.CLASS 保留到字节码上
//        RetentionPolicy.RUNTIME 保留到虚拟机运行时(最多,可通过反射获取)
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatSubmit {

    /**
     * 默认的间隔时间(ms),小于此时间视为重复提交
     */
    int timeout() default 2000;

}

RepeatSubmitAspect 文件

// 开启日志,需要依赖lombok
@Slf4j
// 把一个类定义为切面供容器读取
@Aspect
@Component
public class RepeatSubmitAspect {

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    // 这是一个环绕通知,它会围绕被 @RepeatSubmit 注解标记的方法执行,这里的 repeatSubmit 与下面的参数对应
    @Around("@annotation(repeatSubmit)")
    public Object around(ProceedingJoinPoint point, RepeatSubmit repeatSubmit) throws Throwable {

        // 获取用户的token验证,这里项目用的是 header 里的  Authorization 参数
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String requestToken = request.getHeader("Authorization");

        // 获取注解
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();

        // 获取类,方法
        String className = method.getDeclaringClass().getName();
        String methodName = method.getName();

        // 组装key:用户唯一标识+操作类+方法
        String key = requestToken + "#" + className + "#" + methodName;
        String keyHashCode = String.valueOf(Math.abs(key.hashCode()));
        log.info("key:{},keyHashcode:{}", key, keyHashCode);

        //获取超时时间
        int timeOut = repeatSubmit.timeout();
        log.info("超时时间{}", timeOut);

        //  从缓存给中根据key获取数据
        String value = redisTemplate.opsForValue().get(keyHashCode);

        if (value != null) {
            log.info("重复提交");
            // 如果value不为空; return  "请勿重复提交";
            return new ResponseBean(Constants.CODE_SUCCESS, "重复提交,稍后重试", "");

        } else {
            log.info("首次提交");
            // value为空,则加入缓存,并设置过期过期时间
            redisTemplate.opsForValue().set(keyHashCode, "1", timeOut, TimeUnit.MILLISECONDS);
        }

        //执行Object
        Object object = point.proceed();

        return object;
    }
}

标签:key,springboot,重复,token,提交,ElementType,String
From: https://blog.51cto.com/u_16159391/6499470

相关文章

  • 直播平台怎么搭建,vue 中判断数组中是否有重复的数据
    直播平台怎么搭建,vue中判断数组中是否有重复的数据  isRepeat(v){   letobj={}   for(letiinv){    if(obj[v[i]]){     returntrue    }    obj[v[i]]=true   }   returnfalse  },​ 以上就是......
  • springboot整合cache缓存
    第一步:在pom.xml文件中导入对应坐标<!--cache--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>第二步:启用缓存在启动......
  • springboot 解决跨域问题
    什么是跨域指从一个域名网页去请求另一域名页面的资源,比如baidu.com请求google.com中的资源,但是这种情况是不允许的,因为由浏览器的同源策略,使浏览器对js增加安全限制,即就是阻止不同域下的js进行交互。判断域是否相同是通过判断协议、域名、端口中有任何一个不同,则为不同的域......
  • springboot整合redis
    1、添加依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>2、配置redis通过spring.redis.xxx来配置redis的信息spring.redis.hos......
  • springboot整合持久层
    springboot整合持久层1、整合mybatis这里以多数据源为例第一步创建springboot时,选上mybatis依赖在添加数据库驱动依赖:<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.23<......
  • springboot整合mongodb
    springboot整合mongodb整合mongodb其实与整合redis相差不大1、依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependency&......
  • SEO自动提交URL到站长平台
    近期需要对多个网站进行优化,然而每次手动将URL提交至百度显得非常麻烦。虽然使用了百度自动提交代码,但仍有不便之处。为此,我写了以下脚本,既可单独使用,也可同时使用。尽管可定期访问URL文件,但日志中却常常会出现404错误、权限不足等问题,这使人疑惑是否提交成功。以下代码可直接执行......
  • springboot 中使用 redis 处理接口的幂等性
    什么是接口幂等性?数学中:在一次元运算为幂等时,其作用在任一元素两次后会和其作用一次的结果相同;在二次元运算为幂等时,自己重复运算的结果等于它自己的元素。计算机学中:幂等指多次操作产生的影响只会跟一次执行的结果相同,通俗的说:某个行为重复的执行,最终获取的结果是相同的,不会因......
  • 代码随想录算法训练营第八天| 28. 实现 strStr() 459.重复的子字符串
    28.实现strStr()  难点:1,制作KMP算法2,next数组要求的是,找到的下标:0/s[i]==s[j]才可以跳出来代码:1vector<int>getNextList(stringneedle)2{3vector<int>next(needle.size());4intj=0;5next[0]=0;67for(inti=1;i......
  • SpringBoot快速整合RabbitMq小案例
    对于一个直接创建的springBoot项目工程来说,可以按照以下步骤使用rabbitmq添加依赖:添加rabbitMQ的依赖。<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency>配置连接:在配置文件中配置虚拟主......