Spring AOP + Redis解决重复提交的问题
Spring AOP + Redis解决重复提交的问题
用户在点击操作的时候,可能会连续点击多次,虽然前端可以通过设置按钮的disable的属性来控制按钮不可连续点击,但是如果别人拿到请求进行模拟,依然会出现问题,项目是用JWT进行认证的,所以用的token+url来作为key,value无所谓,因为用不到value
1.自定义注解
/*** 自定义不重复提交的注解*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatSubmit {/*** 设置请求锁定时间 默认锁定一分钟 防止死锁* @return*/int lockTime() default 60;}
2.自定义AOP
/*** 自定义不重复提交的切面*/
@Slf4j
@Aspect
@Component
public class RepeatSubmitAspect {@Autowiredprivate RedisUtil redisUtil;@Pointcut("@annotation(noRepeatSubmit)")public void pointCut(NoRepeatSubmit noRepeatSubmit) {}@Around("pointCut(noRepeatSubmit)")public Object around(ProceedingJoinPoint pjp, NoRepeatSubmit noRepeatSubmit) {int lockSeconds = noRepeatSubmit.lockTime();ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();String key = getKey(request);try {Boolean isLock = redisUtil.tryLock(key);// 如果缓存中有这个url视为重复提交if (!isLock) {// 执行前 添加锁redisUtil.addLock(key, 0, lockSeconds);Object o = pjp.proceed();return o;} else {log.info("重复提交");return ResponseData.oferror("请勿重复提交");}} catch (Throwable e) {e.printStackTrace();log.error("验证重复提交时出现未知异常!");throw new RuntimeException(e);}finally {// 执行后 删除锁redisUtil.releaseLock(key);}}private String getKey(HttpServletRequest request) {String token = request.getHeader("Authorization");String key = token + ":" + request.getServletPath();return key;}}
3.Redis工具类
和重复提交无关的Redis操作方法我都给删除了,因为占空间
/*** @author minalz* @Description Redis工具类* @create 2020-01-29 21:21*/
@Component
public final class RedisUtil {@Resourceprivate RedisTemplate<String, Object> redisTemplate;/*** 普通缓存获取** @param key 键* @return 值*/public Object get(String key) {return key == null ? null : redisTemplate.opsForValue().get(key);}/*** 普通缓存放入并设置时间** @param key 键* @param value 值* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期* @return true成功 false 失败*/public boolean set(String key, Object value, long time) {try {if (time > 0) {redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);} else {set(key, value);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除缓存** @param key 可以传一个值 或多个*/@SuppressWarnings("unchecked")public void del(String... key) {if (key != null && key.length > 0) {if (key.length == 1) {redisTemplate.delete(key[0]);} else {redisTemplate.delete(CollectionUtils.arrayToList(key));}}}/*** 获取分布式锁* @return*/public Boolean tryLock(String key){Object o = this.get(key);if(o != null){return true;}return false;}/*** 添加锁*/public void addLock(String key, Object value, int time){this.set(key, value,time);}/*** 释放锁*/public void releaseLock(String key){this.del(key);}
}
4.统一返回的封装对象
/*** 接口返回封装对象*/
public class ResponseData22 implements Serializable {private static final long serialVersionUID = 1L;public String code = "200"; // 200:成功 01:失败public String msg = "OK";public ResponseData22() {}public ResponseData22(String type, String message) {this.code = type;this.msg = message;}public static ResponseData22 oferror(String message){return new ResponseData22("01",message);}public static ResponseData22 ofok(){return new ResponseData22("200","OK");}}
5.测试方法
在测试方法上添加@NoRepeatSubmit(lockTime = 300)
@PostMapping("/normal")
@NoRepeatSubmit(lockTime = 300)
public ResponseData normal() {ResponseData responseData = new ResponseData();responseData.msg = "我是普通用户";return responseData;
}
相关文章:

转:Flash 插件面板 DragonBonesDesignPanel 的绿色安装方法
最近在cocos2d-js下捣腾Dragonbones。转一个文章,大家可以参考安装Dragonbones。关于这个Dragonbones,5月份的时候还用得好好的,cocos2d-js还能妥妥的加载。最近就不行了,原来默默的升级了。还是得找回原来的2.0版本,后…

任务18:控制反转
控制反转 实现你的依赖,采用什么依赖,不由你自己决定,这个控制交给IOC容器。 这里所有的实现都不由你自己决定,我们只需要传给你就可以了。谁来传呢?容器来传给他 内存的Repository,这里实现的比较简单。 这…

Quixel megascans模型材质贴图合集包
Quixel megascans是一个在线高分辨率扫描模型和贴图库,一致的PBR校准的表面,植被,和三维扫描模型,还包括用于管理的桌面应用、混合和输出你的扫描数据的程序。它的产品已经与游戏和电影工作室合作。 quixel megascans可以帮助您创…

Java学习总结:35(数字操作类)
Java的数字操作类 一.Math类 Math类是一个专门用来进行数学计算的操作类,它提供了一系列的数学计算方法。在Math类里面提供的一切方法都是static型方法,所以可以直接由类名称进行调用。 例:观察四舍五入操作 package Project.Study.MathC…

STL笔记(5)条款49:学习破解有关STL的编译器诊断信息
STL笔记(5)条款49:学习破解有关STL的编译器诊断信息 条款49:学习破解有关STL的编译器诊断信息 用一个特定的大小定义一个vector是完全合法的, vector<int> v(10); // 建立一个大小为10的vector而string在很多…

执子之手,与子偕老。你同意么?
(1):5岁的时候,我说我爱你。你歪着脑袋,眨着水晶般的大眼睛,疑惑地问我:“什么意思呀?” (2):15岁的时候,我说:"我爱你".你的脸红得像火烧云,头深深地低着,摆弄著衣襟&…

34种墨西哥植物模型 Globe Plants – Bundle 34 Mexican Plants
Globe Plants Bundle 34墨西哥植物(3D模型)包括15种3D树木、灌木和肉质植物,用于南美洲的风景、住宅、花园和一般景观美化目的,特别是墨西哥,具有85种独特的照片逼真质量的3D植物模型,具有多种形式,可用于您的许多场景…

Java学习总结:36(日期处理类)
日期处理类 Date类 Date类常用方法 No.方法类型描述1public Date()构造实例化Date类对象2public Date(long date)构造将数字变为Date类对象,long为日期时间数据3public long getTime()普通将当前的日期时间变为long型 例:取得当前的日期时间 package…
最强的篮球队和马尔可夫模型
打篮球经常遇到这种情况,11个人,分4、4、3共三套,一群人少时间玩,在一个失败的团队的人下阵来填补空缺。因此,我认为,,会不会出现一个最强组合,使得这4个人一直赢比赛呢?…

1677: [Usaco2005 Jan]Sumsets 求和
1677: [Usaco2005 Jan]Sumsets 求和 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 626 Solved: 348[Submit][Status]Description Farmer John commanded his cows to search for different sets of numbers that sum to a given number. The cows use only numbers that ar…

通过CPAN安装Perl模块
第一步,进入CPAN shell: sudo perl -MCPAN -e shell 第一次运行会问你一些问题,一般来说缺省答案就好 第二步,执行安装程序,例如安装LWP:UserAgent cpan>install LWP:UserAgent 还有一个二合一的命令,效…

Python3和Raspberry Pi最全面最直接的课程
在一门课程中学习Python 3基础知识、高级Python、科学Python、Raspberry Pi、硬件和物联网项目 教程获取:Python3和Raspberry Pi最全面最直接的课程 – 云桥网络-CG技术学习平台 你会学到: Python 3基础 Python 3高级概念 Raspberry Pi的设置和使用 Scientific Py…

Java学习总结:37(比较器)
比较器 Arrays类 No.方法类型描述1public static boolean equals(int [] a,int [] a2)普通判断两个数组是否相等,此方法被重载多次,可以判断各种数据类型的数组2public static void fill(int [] a,int val)普通将指定内容填充到数组中,此方…

探究rh6上mysql5.6的主从、半同步、GTID多线程、SSL认证主从复制
http://407711169.blog.51cto.com/6616996/1203973/转载于:https://www.cnblogs.com/zengkefu/p/5042351.html

文字转语音(jacob)
近期项目中出现在离线情况下文字转语音的需求 经过尝试发现jacob还不错 注:只适用于windows系统环境 以下为开发记录: 1.pom.xml中引入jacob.jar <dependency><groupId>com.hynnet</groupId><artifactId>jacob</artifactId&…

log4j配置说明
2019独角兽企业重金招聘Python工程师标准>>> 一.参数意义说明 输出级别的种类 ERROR、WARN、INFO、DEBUG ERROR 为严重错误 主要是程序的错误 WARN 为一般警告,比如session丢失 INFO 为一般要显示的信息,比如登录登出 DEBUG 为程序的调试信息…

Python 无法安装PyAudio问题
一、错误与原因 在Windows上没有用于Python 3.7的轮子(预构建包)(有一个用于Python 2.7和3.4到3.6),因此需要在PC上准备构建环境以使用此包。因为有些软件包很难在Windows上构建,所以找到3.7的轮子更容易一…

7-4 水仙花数
7-4 水仙花数 水仙花数是指一个N位正整数(N≥3),它的每个位上的数字的N次幂之和等于它本身。例如:153135333。本题要求编写程序,计算所有N位水仙花数。 输入格式: 输入在一行中给出一个正整数N(3≤N≤7)。…

Unreal Engine4 可视化虚拟现实全流程学习教程
课程目标: 这是一套专门为设计院,三维动画公司、效果图公司、景观规划公司、以及有志于进入这些行业创业的公司和人们量身定制的一套虚拟漫游高级教材。 在这套教学里面,我们能够从头开始了解到一个效果图级别的虚拟漫游是怎么制作出来的&…

用python的numpy作线性拟合、多项式拟合、对数拟合
转自:http://blog.itpub.net/12199764/viewspace-1743145/ 项目中有涉及趋势预测的工作,整理一下这3种拟合方法:1、线性拟合-使用mathimport mathdef linefit(x , y): N float(len(x)) sx,sy,sxx,syy,sxy0,0,0,0,0 for i in range(…

Java中的简单工厂模式(转)
Java中的简单工厂模式 举两个例子以快速明白Java中的简单工厂模式:女娲抟土造人话说:“天地开辟,未有人民,女娲抟土为人。”女娲需要用土造出一个个的人,但在女娲造出人之前,人的概念只存在于女娲的思想里面…

Math.toRadians()与 Math.toDegrees()方法介绍
strictfp 的意思是FP-strict,也就是说精确浮点的意思。在Java虚拟机进行浮点运算时,如果没有指定strictfp关键字时,Java的编译器以及运 行环境在对浮点运算的表达式是采取一种近似于我行我素的行为来完成这些操作,以致于得到的结果往往无法令你满意。因此如果你想让你的浮点运算更加精确, 而且不会因为不同的硬件平台所执行的结果不一致的话,那就请用关键字strictfp。如果你想让你的浮点运算更加精确,而且不会因为不同的硬件平台所执行的结果不一致的话,可以用关键字strictfp.

Linux命令基础6-mkdir命令
mkdir是英文单词make directory的缩写。mkdir就是用来创建路径,一般就是用来创建文件夹的。 语法 mkdir (选项)(参数) 选项 -Z:设置安全上下文,当使用SELinux时有效; -m<目标属性>或--mode<目标属性>建立目录的同时设…

原子性,可见性,有序性详解及DCL单例模式两次校验的目的(拓展懒汉式,饿汉式)
进入以后进行第二次判断,是因为,对于首个拿锁者,它的时段instance肯定为null,那么进入new Singleton()对象创建,而在首个拿锁者的创建对象期间,可能有其他线程同步调用getInstance(),那么它们也会通过if进入到同步块试图拿锁然后阻塞。如果能够保证2,3的顺序那么就不会存在安全问题,但是实际因为JIT和处理器会对代码进行优化重排序,那么可能会2,3的顺序颠倒,那么就有可能会出现一个线程拿到了一个未被初始完成的对象,从而引发安全问题。,那么在这种情况下,会出现多个实例对象。

3ds Max中的V-Ray学习
时长3h 30m 大小解压后:2.73G 包含项目文件 1280X720 MP4 语言:英语中英文字幕(根据原英文字幕机译更准确) 3ds Max中的V-Ray简介:官方V-Ray导师 云桥网络 获取课程:3ds Max中的V-Ray学习 Introduction To V-Ray in 3…

7-5 二分法求多项式单根 (20分)
二分法求函数根的原理为:如果连续函数f(x)在区间[a,b]的两个端点取值异号,即f(a)f(b)<0,则它在这个区间内至少存在1个根r,即f( r )0。 二分法的步骤为: 检查区间长度,如果小于给定阈值,则停…

JAVA的instanceOf什么时候用
我个人理解的一个应用场合就是,当你拿到一个对象的引用时(例如参数),你可能需要判断这个引用真正指向的类。所以你需要从该类继承树的最底层开始,使用instanceof操作符判断,第一个结果为true的类即为引用真…

解决谷歌浏览器在非https下限制获取多媒体对象(音视频)的解决方式
1、浏览器输入:chrome://flags/ 2、输入你要允许的域名地址或ip端口地址(如下图)

After Effects CS4 期末考试卷
AECS4考试A卷转载于:https://blog.51cto.com/hnxdd/1593985

数据图表之圆柱图
需求是这样的,需要一个圆柱实现展示内存的占用变化。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><style>.column{position: relative;width: 300px;height:…