实现原理:

  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 { }

最新文章

  1. XML 详解
  2. Node.js入门:事件机制
  3. Android studio 自定义打包APK名称
  4. linux之开发板与宿主机-GDB远程调试
  5. Linux性能及调优指南(翻译)之Linux内存架构
  6. kafka相关应用
  7. 基于visual Studio2013解决C语言竞赛题之0704字符串长度
  8. HDURevenge of Segment Tree(第二长的递增子序列)
  9. [APIO2013]
  10. 服务器资源监控插件(jmeter)
  11. HTTP学习总结
  12. NBC朴素贝叶斯分类器 ————机器学习实战 python代码
  13. ningx.conf location
  14. JAVA中MAP转LIST
  15. Ajax cross domain
  16. PropertyGrid 重难点总结 转
  17. gcc编译工具生成动态库和静态库之一----介绍
  18. 支付宝APP支付,提示代码 ALIN10070
  19. 使用Gulp
  20. 给我一对公钥和私钥,我就能破解此RSA

热门文章

  1. 12月21日内容总结——forms组件渲染标签、展示信息、校验数据的一些补充,forms组件参数和源码剖析,modelform组件,Django中间件
  2. App测试Android的闪退总结
  3. 【Spring】Bean注册注解
  4. 我让 ChatGPT 写了个 ChatGPT
  5. C# File、FileInfo、Directory、DirectoryInfo
  6. Javascript中0.1+0.2===0.3?怎么解决这个问题?
  7. sql注入关键字
  8. Java 集合中的排序算法浅析
  9. CF1638E Colorful Operations
  10. LG P4173 残缺的字符串