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

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

springboot實(shí)現(xiàn)防重復(fù)提交和防重復(fù)點(diǎn)擊的示例

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

背景

同一條數(shù)據(jù)被用戶點(diǎn)擊了多次,導(dǎo)致數(shù)據(jù)冗余,需要防止弱網(wǎng)絡(luò)等環(huán)境下的重復(fù)點(diǎn)擊

目標(biāo)

通過(guò)在指定的接口處添加注解,實(shí)現(xiàn)根據(jù)指定的接口參數(shù)來(lái)防重復(fù)點(diǎn)擊

說(shuō)明

這里的重復(fù)點(diǎn)擊是指在指定的時(shí)間段內(nèi)多次點(diǎn)擊按鈕

技術(shù)方案

springboot + redis鎖 + 注解

使用 feign client 進(jìn)行請(qǐng)求測(cè)試

最終的使用實(shí)例

1、根據(jù)接口收到 PathVariable 參數(shù)判斷唯一

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

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

/** * 根據(jù)請(qǐng)求參數(shù)里的 RequestBody 里獲取指定名稱的變量param5的值進(jìn)行接口級(jí)別防重復(fù)點(diǎn)擊 * * @param testId 測(cè)試id * @param requestVo 請(qǐng)求參數(shù) * @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 秒,模擬業(yè)務(wù)邏輯 Thread.sleep(5); return RsVo.success('test is return success'); }

ps: jedis 2.9 和 springboot有各種兼容問(wèn)題,無(wú)奈只有降低springboot的版本了

運(yùn)行結(jié)果

收到響應(yīng):{'succeeded':true,'code':500,'msg':'操作過(guò)于頻繁,請(qǐng)稍后重試','data':null}收到響應(yīng):{'succeeded':true,'code':500,'msg':'操作過(guò)于頻繁,請(qǐng)稍后重試','data':null}收到響應(yīng):{'succeeded':true,'code':500,'msg':'操作過(guò)于頻繁,請(qǐng)稍后重試','data':null}收到響應(yīng):{'succeeded':true,'code':200,'msg':'success','data':'test is return success'}

測(cè)試用例

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 防重復(fù)點(diǎn)擊測(cè)試類 * @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('收到響應(yīng):' + 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('收到響應(yīng):' + kl); }); } System.in.read(); }}

定義一個(gè)注解

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 重復(fù)點(diǎn)擊的切面 * @author daleyzou * @date 2020年09月23日 14:35 * @version 1.4.8 */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface NoRepeatSubmit { /** * 鎖過(guò)期的時(shí)間 * */ int seconds() default 5; /** * 鎖的位置 * */ String location() default 'NoRepeatSubmit'; /** * 要掃描的參數(shù)位置 * */ int argIndex() default 0; /** * 參數(shù)名稱 * */ String name() default '';}

根據(jù)指定的注解定義一個(gè)切面,根據(jù)參數(shù)中的指定值來(lái)判斷請(qǐng)求是否重復(fù)

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; /** * 橫切點(diǎn) */ @Pointcut('@annotation(noRepeatSubmit)') public void repeatPoint(NoRepeatSubmit noRepeatSubmit) { } /** * 接收請(qǐng)求,并記錄數(shù)據(jù) */ @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('操作過(guò)于頻繁,請(qǐng)稍后重試'); } try { Object proceed = joinPoint.proceed(); return proceed; } catch (Throwable throwable) { logger.error('運(yùn)行業(yè)務(wù)代碼出錯(cuò)', throwable); throw new RuntimeException(throwable.getMessage()); } finally { lockService.unLock(key); } } public static Map<String, Object> getKeyAndValue(Object obj) { Map<String, Object> map = Maps.newHashMap(); // 得到類對(duì)象 Class userCla = (Class) obj.getClass(); /* 得到類中的所有屬性集合 */ Field[] fs = userCla.getDeclaredFields(); for (int i = 0; i < fs.length; i++) { Field f = fs[i]; // 設(shè)置些屬性是可以訪問(wèn)的 f.setAccessible(true); Object val = new Object(); try { val = f.get(obj); // 得到此屬性的值 // 設(shè)置鍵值 map.put(f.getName(), val); } catch (IllegalArgumentException e) { logger.error('getKeyAndValue IllegalArgumentException', e); } catch (IllegalAccessException e) { logger.error('getKeyAndValue IllegalAccessException', e); } } logger.info('掃描結(jié)果:' + gson.toJson(map)); return map; }}

項(xiàng)目完整代碼

https://github.com/daleyzou/PreventRepeatSubmit

以上就是springboot實(shí)現(xiàn)防重復(fù)提交和防重復(fù)點(diǎn)擊的示例的詳細(xì)內(nèi)容,更多關(guān)于springboot實(shí)現(xiàn)防重復(fù)提交和防重復(fù)點(diǎn)擊的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Spring
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
高清av一区| 美女视频黄久久| 国产欧美三级| 91午夜精品| 欧美一区=区| 日韩中文字幕亚洲一区二区va在线 | 亚洲精品日韩久久| 亚洲精品在线二区| 欧美偷窥清纯综合图区| 国产精品18| 97精品中文字幕| 久久久久美女| 亚洲免费影院| 欧美日本不卡高清| 精品国产亚洲一区二区三区大结局 | 免费观看久久久4p| 亚洲精品进入| 久久精品 人人爱| 另类欧美日韩国产在线| 国产66精品| 免费久久精品| 中文字幕日韩亚洲| 国产精品高潮呻吟久久久久| 日本激情一区| 久久影视一区| 美女精品一区| 国产欧美一区二区精品久久久 | 久久婷婷久久| 首页亚洲欧美制服丝腿| 日韩极品在线观看| 电影91久久久| 日韩视频在线一区二区三区| 欧美一级二级三级视频| 国产精品原创| 欧美综合二区| 国产精品白丝av嫩草影院| 伊人久久在线| 蜜臀a∨国产成人精品| 国产精品欧美日韩一区| 成人看片网站| 亚洲网址在线观看| 久久精品九色| 欧美在线亚洲综合一区| 欧美天堂一区二区| 神马午夜在线视频| 中文字幕日韩高清在线| 国际精品欧美精品| 性欧美精品高清| 精品欠久久久中文字幕加勒比| 亚洲午夜精品久久久久久app| 亚洲精品自拍| 日韩三区在线| 国产香蕉精品| 欧洲激情综合| 麻豆极品一区二区三区| 久久网站免费观看| 欧美天堂一区| 99视频精品全国免费| 日韩激情av在线| 久久高清免费| 国产精品任我爽爆在线播放| 亚洲精品电影| 美日韩一区二区三区| 国产一区清纯| 欧美aa在线视频| 免费不卡在线观看| 在线精品亚洲欧美日韩国产| 婷婷综合成人| 激情综合自拍| 欧美国产日本| 亚洲一区区二区| 成人小电影网站| 国产欧美日韩一区二区三区在线| 99riav国产精品| 高清av不卡| 欧美天堂一区二区| 精品1区2区3区4区| 91亚洲国产| 国产欧美自拍一区| 日韩中文字幕区一区有砖一区| 国产精品麻豆久久| 欧美一区91| 日韩一区欧美二区| 欧美性感美女一区二区| 国内精品麻豆美女在线播放视频| 亚洲久久在线| 午夜久久99| 人人精品亚洲| 91麻豆国产自产在线观看亚洲| 欧美日韩1区| 免费美女久久99| 国产精品88久久久久久| 国产高清不卡| 久久中文在线| 欧美日本久久| 日本亚洲视频在线| 在线午夜精品| 激情综合在线| 久久久国产亚洲精品| 免费在线播放第一区高清av| 婷婷综合一区| 蜜臀va亚洲va欧美va天堂 | 午夜精品免费| 久久影院一区| 久久精品电影| 精品国模一区二区三区| 成人美女视频| 国产精品99一区二区三| 免费一级欧美片在线观看网站| 国产女人18毛片水真多18精品| 麻豆9191精品国产| 国产免费成人| 欧美中文字幕| 国产精品老牛| 爽好多水快深点欧美视频| 国产精品日本| 视频在线观看一区二区三区| 亚洲一区二区免费看| 国产一级久久| 一区二区电影在线观看| 亚洲精品在线国产| 日韩avvvv在线播放| 日韩高清在线不卡| 婷婷久久免费视频| 日韩福利视频网| 欧美日一区二区在线观看| 欧美精品三级在线| 国产精品www994| 美女精品一区二区| 国产精品99视频| 亚洲91视频| 影音先锋国产精品| 亚洲狼人精品一区二区三区| 91欧美极品| 麻豆91小视频| 黄色aa久久| 久久精品动漫| 国产视频一区三区| 日本一区二区三区中文字幕| 欧美午夜三级| 狠狠久久伊人| 偷拍精品精品一区二区三区| 亚洲午夜精品久久久久久app| 精品日韩毛片| 日韩中文字幕亚洲一区二区va在线| 亚洲欧美日本国产| 国产精品视频3p| 成人黄色av| 亚洲激情精品| 欧美亚洲自偷自偷| 日本一区二区高清不卡| 亚洲二区免费| 中文字幕亚洲在线观看| 国产伦精品一区二区三区千人斩| 91亚洲国产高清| 精品在线99| 亚洲精品乱码久久久久久蜜桃麻豆| 国产美女精品视频免费播放软件| 久久精品理论片| 国产传媒av在线| 99国产精品视频免费观看一公开 | 成人在线免费观看91| 亚洲午夜精品久久久久久app| 免费在线看一区| 国产精品久久久久av蜜臀| 中文字幕人成乱码在线观看| 欧美日韩国产亚洲一区| 欧美综合精品| 久久激情网站| 日韩精品视频中文字幕| 高清日韩中文字幕| 香蕉成人久久| 国产精品亚洲综合在线观看| 欧美sm一区| 日本国产亚洲| 欧美成人基地| 日本精品在线播放| 国产麻豆久久| 日韩激情网站| 成人自拍av| 婷婷综合国产| 日韩在线高清| 亚洲精品国模| 日韩在线短视频| 日韩精品三级| 欧美亚洲精品在线| 国产亚洲欧美日韩在线观看一区二区| 成人va天堂| 国产午夜一区| 亚洲综合不卡| av资源新版天堂在线| 亚洲精品欧洲| 色婷婷精品视频| 国产探花在线精品| 午夜久久影院| 福利片在线一区二区| 亚洲91网站| 国产精品蜜芽在线观看| 日韩福利在线观看| 国产韩日影视精品|