springboot aop本地缓存防止重复提交
实现原理:
- 自定义防止重复提交标记(@RepeatSubmit)。
- 对需要防止重复提交的Congtroller里的mapping方法加上该注解。
- 新增Aspect切入点,为@RepeatSubmitAspect加入切入点。
- 每次提交表单时,Aspect都会保存当前key到reids(须设置过期时间)。
- 重复提交时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本地缓存防止重复提交的更多相关文章
- Springboot 2.x 如何解决重复提交 (本地锁的实践)
有没有遇到过这种情况:网页响应很慢,提交一次表单后发现没反应,然后你就疯狂点击提交按钮(12306就经常被这样怒怼),如果做过防重复提交还好,否则那是什么级别的灾难就不好说了... 本文主要是应用 自 ...
- springboot之本地缓存(guava与caffeine)
1. 场景描述 因项目要使用本地缓存,具体为啥不用redis等,就不讨论,记录下过程,希望能帮到需要的朋友. 2.解决方案 2.1 使用google的guava作为本地缓存 初步的想法是使用googl ...
- AOP实现防止接口重复提交
项目中对于状态变更接口存在重复提交的问题. package com.yxx.survey.foundation.aop; import com.alibaba.fastjson.JSON; impor ...
- JAVA后端生成Token(令牌),用于校验客户端,防止重复提交
转:https://blog.csdn.net/u011821334/article/details/79390980 转:https://blog.csdn.net/joshua1830/artic ...
- Springboot+Redisson自定义注解一次解决重复提交问题(含源码)
前言 项目中经常会出现重复提交的问题,而接口幂等性也一直以来是做任何项目都要关注的疑难点,网上可以查到非常多的方案,我归纳了几点如下: 1).数据库层面,对责任字段设置唯一索引,这是最直接有效 ...
- AOP+Token防止表单重复提交
表单重复提交: 由于用户误操作,多次点击表单提交按钮 由于网速等原因造成页面卡顿,用户重复刷新提交页面 避免表单重复提交的方式: 1.页面上的按钮做防重复点击操作 2.在数据库中可以做唯一约束 3.利 ...
- 使用aop注解实现表单防重复提交功能
原文:https://www.cnblogs.com/manliu/articles/5983888.html 1.这里采用的方法是:使用get请求进入表单页面时,后台会生成一个tokrn_flag分 ...
- springboot——重定向解决刷新浏览器造成表单重复提交的问题(超详细)
原因:造成表单重复提交的原因是当我们刷新浏览器的时候,浏览器会发送上一次提交的请求.由于上一次提交的请求方式为post,刷新浏览器就会重新发送这个post请求,造成表单重复提交. 解决办法: 将请求当 ...
- Spring Boot (一) 校验表单重复提交
一.前言 在某些情况下,由于网速慢,用户操作有误(连续点击两下提交按钮),页面卡顿等原因,可能会出现表单数据重复提交造成数据库保存多条重复数据. 存在如上问题可以交给前端解决,判断多长时间内不能再次点 ...
- SpringBoot--防止重复提交(锁机制---本地锁、分布式锁)
防止重复提交,主要是使用锁的形式来处理,如果是单机部署,可以使用本地缓存锁(Guava)即可,如果是分布式部署,则需要使用分布式锁(可以使用zk分布式锁或者redis分布式锁),本文的分布式锁以red ...
随机推荐
- 12月5日内容总结——JS基础知识及变量常量、基本数据类型、运算符、流程控制、函数、内置对象
目录 一.JS简介 简介 ECMAScript的历史 二.JS基础 1.注释语法 2.引入js的多种方式 3.结束符号 三.变量与常量 编写和运行js代码的两种方式 变量声明 四.基本数据类型 1.数 ...
- 嵌入式Linux—Framebuffer应用编程
Framebuffer 应用编程 Frame的意思是帧,buffer的意思是缓冲区.Framebuffer就是一块内存(硬件设备),里面保存着一帧图像. ioctl()函数解析 ioctl()函数非常 ...
- 线程基础知识10-volatile
1 简介 Volatile保证了可见性和有序性,没有保证原子性. 1.1 保证可见性简介 可见性就是指当一个线程修改了共享变量的值时,其他线程能够立即得知这个修改.volatile变量做到了这一点. ...
- C# System.Threading.Timer 详解及示例
前言 定时器功能在日常开发中也是比较常用的,在 .Net 中实际上总共有五种定时器,分别是:System.Timers.Timer.System.Threading.Timer.System.Wind ...
- JZOJ 2022.07.06【提高组A】模拟
历程 被暴打了 原因是钻进了 \(T4\) 的坑中... 先看完题,发现 \(T4\) 比较有意思,\(T2\) 没有想法 \(T3\) 挺容易,做法似乎很好想 \(T1\) 送分,十几分钟搞定 然后 ...
- ChatGPT API使用介绍
1.概述 随着人工智能技术的不断发展,越来越多的AI产品被应用到各个领域,其中最具代表性的莫过于人工智能语言模型.语言模型是一种可以通过学习大量语言数据来预测文本或语音的技术,其应用范围十分广泛,如智 ...
- vscode+eslint项目规范化,自动格式化配置(项目中用到的)
项目如果没有格式化插件就会变得十分拥挤,并且因为个人的开发习惯不同,会导致多人配合的时候,某些人的格式不能与你的兼容 导致项目大面积冲突,这样一来统一的格式和开发规范就十分必要了. 1.下载使用vsc ...
- vue-seamless-scroll滚动加点赞衔接处数据不同步问题
VUE使用vue-seamless-scroll自动滚动加点赞,因为有两个overhidden导致点击不同同步dom,在代码中会出现两处vue-seamless-scroll上下悬接,悬接处点赞触发没 ...
- PostgreSQL 谁堵塞了谁(锁等待检测)- pg_blocking_pids
一.背景 当一个进程处于等待(被堵塞)状态时,是谁干的?可以使用如下函数,快速得到捣蛋(堵塞别人)的PID. 二.案例 1.会话1 postgres=# begin; BEGIN postgres=# ...
- Python Socket 基础多用户编程
简介 写下这篇小记的原因是想记录一下自己学习Python Socket编程的心路历程.之前在中专的时间学过一些基础的Socket编程,知道了一些比较基础的内容比如基础的socket.bind()类 ...