电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

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

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

瀏覽:9日期: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
相關文章:
主站蜘蛛池模板: 管家婆-管家婆软件-管家婆辉煌-管家婆进销存-管家婆工贸ERP | 背压阀|减压器|不锈钢减压器|减压阀|卫生级背压阀|单向阀|背压阀厂家-上海沃原自控阀门有限公司 本安接线盒-本安电路用接线盒-本安分线盒-矿用电话接线盒-JHH生产厂家-宁波龙亿电子科技有限公司 | 全钢实验台,实验室工作台厂家-无锡市辰之航装饰材料有限公司 | 世界箱包品牌十大排名,女包小众轻奢品牌推荐200元左右,男包十大奢侈品牌排行榜双肩,学生拉杆箱什么品牌好质量好 - Gouwu3.com | 中开泵,中开泵厂家,双吸中开泵-山东博二泵业有限公司 | 细砂提取机,隔膜板框泥浆污泥压滤机,螺旋洗砂机设备,轮式洗砂机械,机制砂,圆锥颚式反击式破碎机,振动筛,滚筒筛,喂料机- 上海重睿环保设备有限公司 | 座椅式升降机_无障碍升降平台_残疾人升降平台-南京明顺机械设备有限公司 | 钢制暖气片散热器_天津钢制暖气片_卡麦罗散热器厂家 | 压接机|高精度压接机|手动压接机|昆明可耐特科技有限公司[官网] 胶泥瓷砖胶,轻质粉刷石膏,嵌缝石膏厂家,腻子粉批发,永康家德兴,永康市家德兴建材厂 | 珠海白蚁防治_珠海灭鼠_珠海杀虫灭鼠_珠海灭蟑螂_珠海酒店消杀_珠海工厂杀虫灭鼠_立净虫控防治服务有限公司 | 开锐教育-学历提升-职称评定-职业资格培训-积分入户 | 拉力测试机|材料拉伸试验机|电子拉力机价格|万能试验机厂家|苏州皖仪实验仪器有限公司 | 江苏农村商业银行招聘网_2024江苏农商行考试指南_江苏农商行校园招聘 | 聚合氯化铝-碱式氯化铝-聚合硫酸铁-聚氯化铝铁生产厂家多少钱一吨-聚丙烯酰胺价格_河南浩博净水材料有限公司 | 电销卡 防封电销卡 不封号电销卡 电话销售卡 白名单电销卡 电销系统 外呼系统 | 亿诺千企网-企业核心产品贸易 | 专业广州网站建设,微信小程序开发,一物一码和NFC应用开发、物联网、外贸商城、定制系统和APP开发【致茂网络】 | 低合金板|安阳低合金板|河南低合金板|高强度板|桥梁板_安阳润兴 北京租车牌|京牌指标租赁|小客车指标出租 | 无锡装修装潢公司,口碑好的装饰装修公司-无锡索美装饰设计工程有限公司 | 运动木地板厂家,篮球场木地板品牌,体育场馆木地板安装 - 欧氏运动地板 | 抖音短视频运营_企业网站建设_网络推广_全网自媒体营销-东莞市凌天信息科技有限公司 | 警方提醒:赣州约炮论坛真的安全吗?2025年新手必看的网络交友防坑指南 | 杭州高温泵_热水泵_高温油泵|昆山奥兰克泵业制造有限公司 | 中式装修设计_室内中式装修_【云臻轩】中式设计机构 | 玉米深加工机械,玉米加工设备,玉米加工机械等玉米深加工设备制造商-河南成立粮油机械有限公司 | 合肥白癜风医院_[治疗白癜风]哪家好_合肥北大白癜风医院 | KBX-220倾斜开关|KBW-220P/L跑偏开关|拉绳开关|DHJY-I隔爆打滑开关|溜槽堵塞开关|欠速开关|声光报警器-山东卓信有限公司 | 代理记账_免费注册公司_营业执照代办_资质代办-【乐财汇】 | 春腾云财 - 为企业提供专业财税咨询、代理记账服务 | 上海佳武自动化科技有限公司| 手板-手板模型-手板厂-手板加工-生产厂家,[东莞创域模型] | 蔡司三坐标-影像测量机-3D扫描仪-蔡司显微镜-扫描电镜-工业CT-ZEISS授权代理商三本工业测量 | 加气混凝土砌块设备,轻质砖设备,蒸养砖设备,新型墙体设备-河南省杜甫机械制造有限公司 | 天长市晶耀仪表有限公司 | 气胀轴|气涨轴|安全夹头|安全卡盘|伺服纠偏系统厂家-天机传动 | 玻纤土工格栅_钢塑格栅_PP焊接_单双向塑料土工格栅_复合防裂布厂家_山东大庚工程材料科技有限公司 | 影视模板素材_原创专业影视实拍视频素材-8k像素素材网 | 北京银联移动POS机办理_收银POS机_智能pos机_刷卡机_收银系统_个人POS机-谷骐科技【官网】 | 校服厂家,英伦校服定做工厂,园服生产定制厂商-东莞市艾咪天使校服 | 蓝牙音频分析仪-多功能-四通道-八通道音频分析仪-东莞市奥普新音频技术有限公司 | 江苏全风,高压风机,全风环保风机,全风环形高压风机,防爆高压风机厂家-江苏全风环保科技有限公司(官网) |