日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

springboot實現防重復提交和防重復點擊的示例

瀏覽:32日期:2023-04-20 10:13:08

背景

同一條數據被用戶點擊了多次,導致數據冗余,需要防止弱網絡等環境下的重復點擊

目標

通過在指定的接口處添加注解,實現根據指定的接口參數來防重復點擊

說明

這里的重復點擊是指在指定的時間段內多次點擊按鈕

技術方案

springboot + redis鎖 + 注解

使用 feign client 進行請求測試

最終的使用實例

1、根據接口收到 PathVariable 參數判斷唯一

/** * 根據請求參數里的 PathVariable 里獲取的變量進行接口級別防重復點擊 * * @param testId 測試id * @param requestVo 請求參數 * @return * @author daleyzou */ @PostMapping('/test/{testId}') @NoRepeatSubmit(location = 'thisIsTestLocation', seconds = 6) public RsVo thisIsTestLocation(@PathVariable Integer testId, @RequestBody RequestVo requestVo) throws Throwable { // 睡眠 5 秒,模擬業務邏輯 Thread.sleep(5); return RsVo.success('test is return success'); }

2、根據接口收到的 RequestBody 中指定變量名的值判斷唯一

/** * 根據請求參數里的 RequestBody 里獲取指定名稱的變量param5的值進行接口級別防重復點擊 * * @param testId 測試id * @param requestVo 請求參數 * @return * @author daleyzou */ @PostMapping('/test/{testId}') @NoRepeatSubmit(location = 'thisIsTestBody', seconds = 6, argIndex = 1, name = 'param5') public RsVo thisIsTestBody(@PathVariable Integer testId, @RequestBody RequestVo requestVo) throws Throwable { // 睡眠 5 秒,模擬業務邏輯 Thread.sleep(5); return RsVo.success('test is return success'); }

ps: jedis 2.9 和 springboot有各種兼容問題,無奈只有降低springboot的版本了

運行結果

收到響應:{'succeeded':true,'code':500,'msg':'操作過于頻繁,請稍后重試','data':null}收到響應:{'succeeded':true,'code':500,'msg':'操作過于頻繁,請稍后重試','data':null}收到響應:{'succeeded':true,'code':500,'msg':'操作過于頻繁,請稍后重試','data':null}收到響應:{'succeeded':true,'code':200,'msg':'success','data':'test is return success'}

測試用例

package com.dalelyzou.preventrepeatsubmit.controller;import com.dalelyzou.preventrepeatsubmit.PreventrepeatsubmitApplicationTests;import com.dalelyzou.preventrepeatsubmit.service.AsyncFeginService;import com.dalelyzou.preventrepeatsubmit.vo.RequestVo;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import java.io.IOException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * TestControllerTest * @description 防重復點擊測試類 * @author daleyzou * @date 2020年09月28日 17:13 * @version 1.3.1 */class TestControllerTest extends PreventrepeatsubmitApplicationTests { @Autowired AsyncFeginService asyncFeginService; @Test public void thisIsTestLocation() throws IOException { RequestVo requestVo = new RequestVo(); requestVo.setParam5('random'); ExecutorService executorService = Executors.newFixedThreadPool(4); for (int i = 0; i <= 3; i++) { executorService.execute(() -> { String kl = asyncFeginService.thisIsTestLocation(requestVo); System.err.println('收到響應:' + kl); }); } System.in.read(); } @Test public void thisIsTestBody() throws IOException { RequestVo requestVo = new RequestVo(); requestVo.setParam5('special'); ExecutorService executorService = Executors.newFixedThreadPool(4); for (int i = 0; i <= 3; i++) { executorService.execute(() -> { String kl = asyncFeginService.thisIsTestBody(requestVo); System.err.println('收到響應:' + kl); }); } System.in.read(); }}

定義一個注解

package com.dalelyzou.preventrepeatsubmit.aspect;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * NoRepeatSubmit * @description 重復點擊的切面 * @author daleyzou * @date 2020年09月23日 14:35 * @version 1.4.8 */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface NoRepeatSubmit { /** * 鎖過期的時間 * */ int seconds() default 5; /** * 鎖的位置 * */ String location() default 'NoRepeatSubmit'; /** * 要掃描的參數位置 * */ int argIndex() default 0; /** * 參數名稱 * */ String name() default '';}

根據指定的注解定義一個切面,根據參數中的指定值來判斷請求是否重復

package com.dalelyzou.preventrepeatsubmit.aspect;import com.dalelyzou.preventrepeatsubmit.constant.RedisKey;import com.dalelyzou.preventrepeatsubmit.service.LockService;import com.dalelyzou.preventrepeatsubmit.vo.RsVo;import com.google.common.collect.Maps;import com.google.gson.Gson;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import java.lang.reflect.Field;import java.util.Map;@Aspect@Componentpublic class NoRepeatSubmitAspect { private static final Logger logger = LoggerFactory.getLogger(NoRepeatSubmitAspect.class); private static Gson gson = new Gson(); private static final String SUFFIX = 'SUFFIX'; @Autowired LockService lockService; /** * 橫切點 */ @Pointcut('@annotation(noRepeatSubmit)') public void repeatPoint(NoRepeatSubmit noRepeatSubmit) { } /** * 接收請求,并記錄數據 */ @Around(value = 'repeatPoint(noRepeatSubmit)') public Object doBefore(ProceedingJoinPoint joinPoint, NoRepeatSubmit noRepeatSubmit) { String key = RedisKey.NO_REPEAT_LOCK_PREFIX + noRepeatSubmit.location(); Object[] args = joinPoint.getArgs(); String name = noRepeatSubmit.name(); int argIndex = noRepeatSubmit.argIndex(); String suffix; if (StringUtils.isEmpty(name)) { suffix = String.valueOf(args[argIndex]); } else { Map<String, Object> keyAndValue = getKeyAndValue(args[argIndex]); Object valueObj = keyAndValue.get(name); if (valueObj == null) { suffix = SUFFIX; } else { suffix = String.valueOf(valueObj); } } key = key + ':' + suffix; logger.info('=================================================='); for (Object arg : args) { logger.info(gson.toJson(arg)); } logger.info('=================================================='); int seconds = noRepeatSubmit.seconds(); logger.info('lock key : ' + key); if (!lockService.isLock(key, seconds)) { return RsVo.fail('操作過于頻繁,請稍后重試'); } try { Object proceed = joinPoint.proceed(); return proceed; } catch (Throwable throwable) { logger.error('運行業務代碼出錯', throwable); throw new RuntimeException(throwable.getMessage()); } finally { lockService.unLock(key); } } public static Map<String, Object> getKeyAndValue(Object obj) { Map<String, Object> map = Maps.newHashMap(); // 得到類對象 Class userCla = (Class) obj.getClass(); /* 得到類中的所有屬性集合 */ Field[] fs = userCla.getDeclaredFields(); for (int i = 0; i < fs.length; i++) { Field f = fs[i]; // 設置些屬性是可以訪問的 f.setAccessible(true); Object val = new Object(); try { val = f.get(obj); // 得到此屬性的值 // 設置鍵值 map.put(f.getName(), val); } catch (IllegalArgumentException e) { logger.error('getKeyAndValue IllegalArgumentException', e); } catch (IllegalAccessException e) { logger.error('getKeyAndValue IllegalAccessException', e); } } logger.info('掃描結果:' + gson.toJson(map)); return map; }}

項目完整代碼

https://github.com/daleyzou/PreventRepeatSubmit

以上就是springboot實現防重復提交和防重復點擊的示例的詳細內容,更多關于springboot實現防重復提交和防重復點擊的資料請關注好吧啦網其它相關文章!

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产精品99一区二区三| 日韩精品成人| 日韩精品看片| 久久久久久免费视频| 国产aa精品| 中文av在线全新| 日韩一级不卡| 欧美久久久网站| 国产精品成人a在线观看| 99热精品久久| 欧美综合二区| 国产精品自在| 成人精品国产亚洲| 亚洲免费黄色| 欧美日韩国产一区二区在线观看| 国产在线日韩精品| 欧美一级精品| 日本精品在线播放| 国产成年精品| 亚洲欧洲另类| 国产精品视频一区二区三区| 日韩中文视频| 日韩一区二区三免费高清在线观看| 国产精品第一国产精品| 中文字幕在线免费观看视频| 亚洲欧美日本日韩| 国产日韩亚洲| 五月天久久网站| 国产精品亚洲产品| 亚洲国产专区| 国产精品久久久久av蜜臀| 国产精品99一区二区| 欧美一级全黄| 久久高清免费| 日韩高清欧美激情| 亚洲综合在线电影| 欧美日韩亚洲一区| 欧美日韩精品一区二区视频| 国产欧美日韩精品一区二区免费 | 日韩精品中文字幕一区二区| 鲁鲁在线中文| 91精品丝袜国产高跟在线| 久久久精品网| 欧美激情视频一区二区三区免费| 亚洲婷婷在线| 国产精品一二| 在线观看一区| 欧美日韩国产免费观看视频| 鲁大师精品99久久久| 免费黄网站欧美| 欧美不卡视频| 天堂√中文最新版在线| 日本精品国产| 久久电影一区| 亚洲一级特黄| 日韩欧美网址| 精品精品99| 国产欧美日韩免费观看| 亚洲图片久久| 欧美~级网站不卡| 精品国产乱码久久久久久1区2匹| 亚洲免费观看高清完整版在线观| 久久精品亚洲人成影院| 精品亚洲自拍| 国产精品毛片久久久| 亚洲精品动态| 亚洲欧美日韩国产| 欧美日韩激情| 久久久影院免费| 美女精品久久| 国产精品对白久久久久粗| 青青国产91久久久久久| 天堂成人免费av电影一区| 亚洲午夜视频| 999精品色在线播放| 电影91久久久| 国产 日韩 欧美 综合 一区| 另类综合日韩欧美亚洲| 国产精东传媒成人av电影| 欧美在线91| 日本成人手机在线| 日韩福利视频网| 日本va欧美va瓶| 日本午夜免费一区二区 | 久久精选视频| 99久久精品网站| 日韩精品免费一区二区在线观看| 精品国产欧美日韩一区二区三区| 国产毛片精品久久| 国产日韩欧美在线播放不卡| 欧美日韩中文| 国产精品一线| 久久午夜影院| 精品丝袜在线| 国产综合精品一区| 99pao成人国产永久免费视频| 亚洲精品午夜av福利久久蜜桃| 国产高清一区| 香蕉久久夜色精品国产| 亚洲欧美视频一区二区三区| 亚洲深夜av| 亚洲深夜福利在线观看| 美国三级日本三级久久99| 日韩一区二区三区免费视频 | 午夜日本精品| 午夜亚洲一区| 日本h片久久| 国产精品xxx在线观看| 老鸭窝一区二区久久精品| 91一区二区| 婷婷亚洲五月色综合| 中文字幕亚洲在线观看| 欧美一级二区| 激情综合五月| 99久久www免费| 国产视频一区三区| 日韩国产在线不卡视频| 国产精品视频首页| а√在线中文在线新版| 精品一区免费| 日韩精品免费视频人成| 欧美精品97| 亚洲午夜黄色| 日韩国产一二三区| 国产91在线精品| 伊人久久亚洲美女图片| 97久久中文字幕| 高清在线一区| 制服诱惑一区二区| 91精品国产自产观看在线| 免费日韩一区二区三区| 欧美搞黄网站| 欧美日韩xxxx| 四虎4545www国产精品| 蜜芽一区二区三区| 国产一区2区在线观看| 99精品99| 久久精品国产在热久久| 在线视频亚洲| 美女久久99| 亚洲在线一区| 久久精品国产福利| 99热精品在线| 精品三级在线| 国产亚洲在线| 欧美激情日韩| 久久最新视频| 超碰在线99| 日本在线一区二区三区| 久久久久国产一区二区| 日韩av电影一区| 欧美日韩在线观看视频小说| 欧美影院视频| 99在线精品免费视频九九视| 国产在视频一区二区三区吞精| 午夜在线精品| 日韩欧美网址| 国产九九精品| 久久亚洲国产精品一区二区| 91视频精品| 91亚洲精品在看在线观看高清| 久久国产影院| 精品一区二区三区免费看| 中文字幕一区二区精品区| 99精品网站| 国产aⅴ精品一区二区三区久久 | 日韩高清不卡| 国产精品伊人| 亚洲精选成人| jiujiure精品视频播放| 激情国产在线| 欧美私人啪啪vps| 伊人精品久久| 夜夜嗨av一区二区三区网站四季av| 欧美日韩在线观看首页| 久久xxx视频| 欧美日韩一视频区二区| 三级在线观看一区二区 | 国产精品成久久久久| 国产乱子精品一区二区在线观看 | 国精品一区二区| 日韩在线观看| 成人在线视频区| 精品少妇av| 久久久精品区| 国产精品777777在线播放 | 日本在线一区二区三区| 日韩在线卡一卡二| 国产视频一区在线观看一区免费| 日本美女一区| 色爱综合网欧美| 国产一区二区久久久久| 免费看久久久| 精品午夜视频| 精品国产亚洲一区二区三区大结局| 久久国产麻豆精品| 日本午夜精品| 国产精品国产三级在线观看| 欧美日韩一区二区三区四区在线观看 | 中文字幕在线看片|