Spring AOP + Redis解决重复提交的问题
生活随笔
收集整理的這篇文章主要介紹了
Spring AOP + Redis解决重复提交的问题
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
Spring AOP + Redis解決重復(fù)提交的問題
用戶在點(diǎn)擊操作的時(shí)候,可能會連續(xù)點(diǎn)擊多次,雖然前端可以通過設(shè)置按鈕的disable的屬性來控制按鈕不可連續(xù)點(diǎn)擊,但是如果別人拿到請求進(jìn)行模擬,依然會出現(xiàn)問題,項(xiàng)目是用JWT進(jìn)行認(rèn)證的,所以用的token+url來作為key,value無所謂,因?yàn)橛貌坏絭alue
1.自定義注解
?
/*** 自定義不重復(fù)提交的注解*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatSubmit {/*** 設(shè)置請求鎖定時(shí)間 默認(rèn)鎖定一分鐘 防止死鎖* @return*/int lockTime() default 60;}
2.自定義AOP
/*** 自定義不重復(fù)提交的切面*/
@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);// 如果緩存中有這個(gè)url視為重復(fù)提交if (!isLock) {// 執(zhí)行前 添加鎖redisUtil.addLock(key, 0, lockSeconds);Object o = pjp.proceed();return o;} else {log.info("重復(fù)提交");return ResponseData.oferror("請勿重復(fù)提交");}} catch (Throwable e) {e.printStackTrace();log.error("驗(yàn)證重復(fù)提交時(shí)出現(xiàn)未知異常!");throw new RuntimeException(e);}finally {// 執(zhí)行后 刪除鎖redisUtil.releaseLock(key);}}private String getKey(HttpServletRequest request) {String token = request.getHeader("Authorization");String key = token + ":" + request.getServletPath();return key;}}
3.Redis工具類
和重復(fù)提交無關(guān)的Redis操作方法我都給刪除了,因?yàn)檎伎臻g
/*** @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);}/*** 普通緩存放入并設(shè)置時(shí)間** @param key 鍵* @param value 值* @param time 時(shí)間(秒) time要大于0 如果time小于等于0 將設(shè)置無限期* @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 可以傳一個(gè)值 或多個(gè)*/@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.統(tǒng)一返回的封裝對象
/*** 接口返回封裝對象*/
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;
}
?
總結(jié)
以上是生活随笔為你收集整理的Spring AOP + Redis解决重复提交的问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2022-2028年中国基因工程药物产业
- 下一篇: 2022-2028年中国基金业投资分析及