实现原理:

  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. 12月23日内容总结——csrf跨站请求伪造、校验策略、相关装饰器,auth认证模块及相关操作,拓展auth_user表

    目录 一.csrf跨站请求伪造 概念引入 概念讲解 二.csrf校验策略 概念讲解 form表单操作csrf策略 ajax请求csrf策略 三.csrf相关装饰器 四.auth认证模块 五.auth认 ...

  2. liinux-目录、文件结构及相关命令

    1.前期必备知识 1.命令提示符 [root@max001 ~]#:root表示用户信息,max001表示主机名称. [root@max001 ~]%:普通用户结尾是$符号. 2.命令格式规范(语法规 ...

  3. springboot 多数据源 实例(sybase、mysql数据库)(上)

    最近项目 需要用到 sybase(sql anywhere).mysql 数据库 两边数据交互 .由于之前对sybase 数据库一点不懂 踩了许多坑 特意记下: 连接 sybase 客户端需要用到 S ...

  4. .NET 支付宝SDK新版 AlipayEasySDK 配置文件详细说明

    config代码: using Tea; namespace Alipay.EasySDK.Kernel { /// <summary> /// 客户端配置参数模型 /// </su ...

  5. Docker部署Nacos自动停止运行

    1.现象 使用docker部署的Nacos在运行一段时间后,就自动停止运行了. 查看docker运行容器,nacos停止了 2.解决 因为是学生购买的轻量级服务器,所以配置很低,出现这种问题我默认是内 ...

  6. JZOJ 4744.同余

    \(\text{Problem}\) \(\text{Solution}\) 考虑 \(60\) 分 设 \(f_{i,j,k}\) 表示前 \(i\) 个数,模 \(j\) 同余 \(k\) 的个数 ...

  7. [EULAR文摘] 新证据: NSAID对AS放射学进展的影响

    新证据: NSAID对AS放射学进展的影响 Sieper J, et al. EULAR 2015. Present ID: OP0145. 背景: 既往有研究显示持续给予NSAID相较于按需给药能在 ...

  8. 小程序动态class与动态style的写法:

    style = "opacity :{{num}}" class = "vp {{opacity == 0 ? 'opacity1':''}}"

  9. Vue js引用警告 “export ‘default‘ (imported as ‘xxx‘) was not found

    问题原因:ES6 编译器识别问题 如果在public.js这样写会有警告export 'default' (imported as 'xxx') was not found export const ...

  10. Postgresql 二进制字符串函数和操作符

    1.SQL 二进制字符串函数和操作符 函数 返回类型 描述 例子 结果 string || string bytea 字符串连接 E'\\\\Post'::bytea || E'\\047gres\\ ...