java后端如何實(shí)現(xiàn)防止接口重復(fù)提交
java后端防止接口重復(fù)提交
利用redis實(shí)現(xiàn)防止前端重復(fù)點(diǎn)擊按鈕重復(fù)提交。
解釋:
此方法是利用AOP+Redis實(shí)現(xiàn)防止接口重復(fù)請(qǐng)求
在需要防止重復(fù)提交的方法上,添加CheckRepeatCommit 注解。
此注解額,有兩個(gè)屬性,channel屬性是當(dāng)前訪問(wèn)的系統(tǒng),redis中key的前綴。
可不填。
expireTime 屬性,是添加了此注解的方法多久之內(nèi)不允許同一用戶重復(fù)請(qǐng)求,默認(rèn)3秒。
防止重復(fù)提交的原理就是:
在每次請(qǐng)求加了CheckRepeatCommit注解的接口時(shí),都會(huì)利用AOP在redis中保存一個(gè)從1開(kāi)始的自增數(shù)字,并設(shè)置此KEY的過(guò)期時(shí)間,當(dāng)后續(xù)同一個(gè)用戶再次請(qǐng)求時(shí),判斷此自增數(shù)字是否已存在并>=1,如果已存在并>=1,拋出異常。
話不多說(shuō),直接上代碼
自定義注解
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckRepeatCommit {
String channel() default "APP";
int expireTime() default 3;
}
定義切面
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
@Component
@Aspect
@Slf4j
public class CheckRepeatCommitAspect {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Pointcut("@annotation(com.upbim.twin.park.common.annotation.CheckRepeatCommit)")
private void checkRepeatCommit() {
}
@Around("checkRepeatCommit()")
public Object checkRepeatCommit(ProceedingJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
Object target = joinPoint.getTarget();
//得到攔截的方法
Method method = getMethodByClassAndName(target.getClass(), methodName);
log.info("驗(yàn)證是否重復(fù)提交:" + "調(diào)用方法:" + method);
//請(qǐng)求的方法名
String className = joinPoint.getTarget().getClass().getName();
String channel = "";
String bizKey = method.getName();
int expireTime = 0;
// 獲取當(dāng)前請(qǐng)求方法的注解,根據(jù)注解配置獲取參數(shù)
CheckRepeatCommit checkRepeatCommit = method.getAnnotation(CheckRepeatCommit.class);
String userNo = SysUserContextHolder.getSysUser().getUserNo();
String key;
if (checkRepeatCommit != null) {
//注解上的描述
channel = checkRepeatCommit.channel();
expireTime = checkRepeatCommit.expireTime();
key = getRepeatCommitLock(channel, className, bizKey, userNo, expireTime);
if (StringUtils.isBlank(key)) {
throw new SystemException(ResultEnum.RE_COMMIT);
}
}
return joinPoint.proceed();
}
/**
* 根據(jù)類和方法名得到方法
*/
public Method getMethodByClassAndName(Class c, String methodName) {
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(methodName)) {
return method;
}
}
return null;
}
public String getRepeatCommitLock(String channel, String module, String bizKey, String userNo, int expireTime) {
if (StringUtils.isEmpty(module) || StringUtils.isEmpty(bizKey)) {
throw new ParamException(ResultEnum.PARAMETER_CHECK_ERROR, "getRepeatCommitLock{} 參數(shù)不能為空!");
}
String redisKey = channel + StrUtil.COLON + module + StrUtil.COLON + bizKey + StrUtil.COLON + userNo;
long count = redisTemplate.opsForValue().increment(redisKey, 1);
if (count == 1) {
if (expireTime == 0) {
expireTime = 60;
}
redisTemplate.expire(redisKey, expireTime, TimeUnit.SECONDS);
return redisKey;
} else {
return null;
}
}
}
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- java如何防止表單重復(fù)提交的注解@RepeatSubmit
- Java使用注解實(shí)現(xiàn)防止重復(fù)提交實(shí)例
- java后臺(tái)防止表單重復(fù)提交方法詳解
- java開(kāi)發(fā)中防止重復(fù)提交的幾種解決方案
- Java防止頻繁請(qǐng)求、重復(fù)提交的操作代碼(后端防抖操作)
- Java后端限制頻繁請(qǐng)求和重復(fù)提交的實(shí)現(xiàn)
- Java中防止數(shù)據(jù)重復(fù)提交超簡(jiǎn)單的6種方法
- Java結(jié)合redis實(shí)現(xiàn)接口防重復(fù)提交
- Java表單重復(fù)提交的避免方法
- JAVA防止重復(fù)提交Web表單的方法
- Java防止重復(fù)提交訂單的實(shí)現(xiàn)示例
相關(guān)文章
在 Spring Boot 項(xiàng)目中使用分頁(yè)插件的兩種常見(jiàn)方式示例詳解
本文介紹了SpringBoot項(xiàng)目中兩種分頁(yè)插件的使用方法:MyBatis-Plus分頁(yè)插件和PageHelper插件,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2025-10-10
SpringCloud feign服務(wù)熔斷下的異常處理操作
這篇文章主要介紹了SpringCloud feign服務(wù)熔斷下的異常處理操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
Java AbstractMethodError案例分析詳解
這篇文章主要介紹了Java AbstractMethodError案例分析詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
java 實(shí)現(xiàn)字節(jié)流和字節(jié)緩沖流讀寫(xiě)文件時(shí)間對(duì)比
這篇文章主要介紹了java 實(shí)現(xiàn)字節(jié)流和字節(jié)緩沖流讀寫(xiě)文件時(shí)間對(duì)比,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-01-01
Java面試題沖刺第二十六天--實(shí)戰(zhàn)編程2
這篇文章主要為大家分享了最有價(jià)值的三道java實(shí)戰(zhàn)編程的面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,感興趣的小伙伴們可以參考一下2021-08-08
Spring?Boot?3.x?開(kāi)發(fā)中緩存分區(qū)策略導(dǎo)致的數(shù)據(jù)傾斜問(wèn)題及解決方案
本文將深入剖析緩存分區(qū)導(dǎo)致數(shù)據(jù)傾斜的成因,并提供在?Spring?Boot?3.x?環(huán)境下的系統(tǒng)性解決方案,感興趣的朋友跟隨小編一起看看吧2026-04-04
Java高級(jí)開(kāi)發(fā)高頻面試題完整版(由淺入深&高薪必背)
Java是一個(gè)支持并發(fā)、基于類和面向?qū)ο蟮挠?jì)算機(jī)編程語(yǔ)言,這篇文章主要介紹了Java高級(jí)開(kāi)發(fā)高頻面試題的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2026-03-03
從零開(kāi)始設(shè)計(jì)基于SpringBoot的Serverless(本地函數(shù)計(jì)算)引擎
最近突然冒出一個(gè)想法:能不能用SpringBoot自己實(shí)現(xiàn)一個(gè)類似AWS Lambda或阿里云函數(shù)計(jì)算的執(zhí)行引擎,所以下面我們就來(lái)看看如何從零開(kāi)始設(shè)計(jì)一套基于SpringBoot的Serverless執(zhí)行框架吧2025-07-07

