实现原理:

  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. immutable.js学习笔记(八)----- immutable.js对象 和 原生对象的相互转换

    一.原生对象转换为immutable.js对象 fromJS 栗子一: 栗子二: 如果数组里面有对象,对象里面有数组,怎么转换呢 复杂结构的转换 二.immutable.js对象转换为原生对象 toJ ...

  2. eclipse配置JD-Eclipse反编译java的class文件 【2021年最新版使用教程】

    简介 就是像eclipse那样ctrl+左键点击查看源码,不过eclipse本身不带这种插件而已 0x00 下载JD-eclipse 官网:http://java-decompiler.github. ...

  3. C++并发-同步并发

    1.等待事件 std::mutex m; void wait() { std::unique_lock<std::mutex> lk(m); lk.unlock(); std::this_ ...

  4. The Missing Semester - 第三讲 学习笔记

    第三讲 Vim 课程视频地址:https://www.bilibili.com/video/BV1Dy4y1a7BW 课程讲义地址:https://missing-semester-cn.github ...

  5. Centos7作为VNCserver,本地使用VNCViewer连接

    1.概念 VNC是一个远程连接工具 VNC is used to display an X windows session running on another computer. Unlike a ...

  6. 记一次完整的PHP代码审计——yccms v3.4审计

    一.环境搭建与使用工具 (一)环境搭建 打开源码查看安装要求 PHP 5.4+,Mysql 5.0.*,直接使用phpstudy配置即可 查看源码目录结构,发现是mvc模式的,那么我们重点关注的就是c ...

  7. Cesium CallbackProperty(十五)

    Cesium中的entities可以随时间变化长度高度,主要依赖于CallbackProperty函数. 因为使用CallbackProperty,cesium中一切可视化的要素都可以与时间联系起来. ...

  8. 代码随想录算法训练营day13

    基础知识 二叉树基础知识 二叉树多考察完全二叉树.满二叉树,可以分为链式存储和数组存储,父子兄弟访问方式也有所不同,遍历也分为了前中后序遍历和层次遍历 Java定义 public class Tree ...

  9. 打印出来的数据{ob: observer}、vue 中 [__ob__: Observer]问题

    问题效果: 理想效果: 解决方案:JSON.parse(JSON.stringify( ob )) 首先我们要把这个数据获取原始数据 JSON.stringify([data])   变成字符串 然后 ...

  10. Django中多数据库的配置,实现分库分表,主从复制,读写分离

    在django项目中, 一个工程中存在多个APP应用很常见. 有时候希望不同的APP连接不同的数据库,这个时候需要建立多个数据库连接. 1. 修改项目的 settings 配置 在 settings. ...