实现原理:

  1. 自定义防止重复提交标记(@RepeatSubmit)。
  2. 对需要防止重复提交的Congtroller里的mapping方法加上该注解。
  3. 新增Aspect切入点,为@RepeatSubmitAspect加入切入点。
  4. 每次提交表单时,Aspect都会保存当前key到reids(须设置过期时间)。
  5. 重复提交时Aspect会判断当前redis是否有该key,若有则拦截。
public enum CaffeineCaches {

    baseUsers,
userRequestUrls(3L, 1000); private int maxSize = 1000; //默认最大缓存数量
private Long ttl = 3600L; //默认过期时间(单位:秒) CaffeineCaches(){
} CaffeineCaches(Long ttl,int maxSize){
this.ttl = ttl;
this.maxSize = maxSize;
} public int getMaxSize(){
return maxSize;
} public Long getTtl(){
return ttl;
}
}
@Configuration
public class CacheConfig { @Bean
public CacheManager cacheManager(){
SimpleCacheManager manager = new SimpleCacheManager();
List<CaffeineCache> cacheList = new ArrayList<>();
for(CaffeineCaches ca: CaffeineCaches.values()){
cacheList.add(new CaffeineCache(ca.name(),
Caffeine.newBuilder().recordStats()
.expireAfterWrite(ca.getTtl(), TimeUnit.SECONDS)
.maximumSize(ca.getMaxSize())
.build()));
}
manager.setCaches(cacheList);
return manager;
} }
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 RepeatSubmit {
}
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Aspect
@Component
public class RepeatSubmitAspect { @Autowired
private CacheManager caffeineCacheManager; @Pointcut("@annotation(com.xx.annotation.RepeatSubmit)")
public void logPointCut() {
} @Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
Cache cache = caffeineCacheManager.getCache(CaffeineCaches.userRequestUrls.name()); HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
String ip = IPUtils.getIpAddr(request);
String url = request.getServletPath(); String key = ip.replaceAll("\\.", "") + "-" + url;
SysUser u = (SysUser) SecurityUtils.getSubject().getPrincipal();
log.info(">>>>>>>>>>>>请求ip: {} 请求url: {} 当前用户:{}", ip, url, u != null ? u.getUid() : "anno"); Object result = null;
if (u != null && !StringUtils.isEmpty(u.getUid())) {
key = key + "-" + u.getUid() + "-" + url;
if (cache.get(key) == null ) {
result = point.proceed();
cache.put(key, 1);
} else {
throw new RRException(-91002);
}
} else { // 匿名
result = point.proceed();
} return result;
} }
@RepeatSubmit
@PostMapping("/x/x")
public R x(@RequestBody x x) { }

.cnblogs_code { }

springboot aop本地缓存防止重复提交的更多相关文章

  1. Springboot 2.x 如何解决重复提交 (本地锁的实践)

    有没有遇到过这种情况:网页响应很慢,提交一次表单后发现没反应,然后你就疯狂点击提交按钮(12306就经常被这样怒怼),如果做过防重复提交还好,否则那是什么级别的灾难就不好说了... 本文主要是应用 自 ...

  2. springboot之本地缓存(guava与caffeine)

    1. 场景描述 因项目要使用本地缓存,具体为啥不用redis等,就不讨论,记录下过程,希望能帮到需要的朋友. 2.解决方案 2.1 使用google的guava作为本地缓存 初步的想法是使用googl ...

  3. AOP实现防止接口重复提交

    项目中对于状态变更接口存在重复提交的问题. package com.yxx.survey.foundation.aop; import com.alibaba.fastjson.JSON; impor ...

  4. JAVA后端生成Token(令牌),用于校验客户端,防止重复提交

    转:https://blog.csdn.net/u011821334/article/details/79390980 转:https://blog.csdn.net/joshua1830/artic ...

  5. Springboot+Redisson自定义注解一次解决重复提交问题(含源码)

    前言   项目中经常会出现重复提交的问题,而接口幂等性也一直以来是做任何项目都要关注的疑难点,网上可以查到非常多的方案,我归纳了几点如下:   1).数据库层面,对责任字段设置唯一索引,这是最直接有效 ...

  6. AOP+Token防止表单重复提交

    表单重复提交: 由于用户误操作,多次点击表单提交按钮 由于网速等原因造成页面卡顿,用户重复刷新提交页面 避免表单重复提交的方式: 1.页面上的按钮做防重复点击操作 2.在数据库中可以做唯一约束 3.利 ...

  7. 使用aop注解实现表单防重复提交功能

    原文:https://www.cnblogs.com/manliu/articles/5983888.html 1.这里采用的方法是:使用get请求进入表单页面时,后台会生成一个tokrn_flag分 ...

  8. springboot——重定向解决刷新浏览器造成表单重复提交的问题(超详细)

    原因:造成表单重复提交的原因是当我们刷新浏览器的时候,浏览器会发送上一次提交的请求.由于上一次提交的请求方式为post,刷新浏览器就会重新发送这个post请求,造成表单重复提交. 解决办法: 将请求当 ...

  9. Spring Boot (一) 校验表单重复提交

    一.前言 在某些情况下,由于网速慢,用户操作有误(连续点击两下提交按钮),页面卡顿等原因,可能会出现表单数据重复提交造成数据库保存多条重复数据. 存在如上问题可以交给前端解决,判断多长时间内不能再次点 ...

  10. SpringBoot--防止重复提交(锁机制---本地锁、分布式锁)

    防止重复提交,主要是使用锁的形式来处理,如果是单机部署,可以使用本地缓存锁(Guava)即可,如果是分布式部署,则需要使用分布式锁(可以使用zk分布式锁或者redis分布式锁),本文的分布式锁以red ...

随机推荐

  1. 腾讯出品小程序自动化测试框架【Minium】系列(五)API详解(中)

    写在前面 又有好久没更新小程序自动化测试框架Minium系列文章了,主要真的太忙,尽量做到每周一更吧,还请大家能够理解! 上篇文章为大家分享关于Minium中Minium.App模块的API 使用,接 ...

  2. Salesforce LWC学习(四十一) If:true 即将弃用?

    本篇参考: https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.reference_dir ...

  3. Nginx10 Lua入门 + openresty

    1 Idea中创建Lua项目 lua官网:https://www.lua.org/ 1.1 添加插件,重启idea 1.2 创建项目 file-New Project 1.3 创建lua文件 1.4 ...

  4. Svelte框架结合SpreadJS实现表格协同文档

    SpreadJS是葡萄城结合 40 余年专业控件技术和在电子表格应用领域的经验而推出的纯前端表格控件.作为一个类Excel控件,SpreadJS如何实现当前比较流行的表格协同呢?本篇文章将简单介绍一下 ...

  5. 【TS】泛型以及多个泛型参数

    泛型 给函数或者属性定义类型的时候,类型是固定的,当业务发生变动时可能不好维护,例如:函数类型固定为string,后续需求更改不好维护,比如需要传入number类型,那么这个函数就不适用了 funct ...

  6. JavaScript的this指向详解

    一.概念: 函数的上下文(this)由调用函数的方式决定,function是"运行时上下文"策略: 函数如果不调用,则不能确定函数的上下文. 二.规则: 对象打点调用它的方法函数, ...

  7. 加密,各种加密,耙梳加密算法(Encryption)种类以及开发场景中的运用(Python3.10)

    不用说火爆一时,全网热议的Web3.0区块链技术,也不必说诸如微信支付.支付宝支付等人们几乎每天都要使用的线上支付业务,单是一个简简单单的注册/登录功能,也和加密技术脱不了干系,本次我们耙梳各种经典的 ...

  8. Commons-Collections反序列化

    Java反序列化漏洞 Commons Collections Apache Commons 是 Apache 软件基金会的项目.Commons Collections 包为 Java 标准的 Coll ...

  9. 关于dynamic类型

    动态类型是从C#4才开始有的,随着DLR一起引人的. 大部分时候的行为如同object类型,对应的IL代码也是object类型. 它的特点是编译时会忽略在dynamic上进行的操作,如调用方法,读写属 ...

  10. dotnet总结

    初衷: 搞了几年.Net ,一直没在博客园做过系统的总结,并打算按照下面的结构来写 语言层面 类型系统 [查看]: https://www.cnblogs.com/francisXu/p/136027 ...