我们在做web应用的时候通常会遇到前端提交按钮重复点击的场景,在某些新增操作上就需要做幂等性限制来保证数据的可靠性。下面来用java aop实现幂等性校验。
一:首先我们需要一个自定义注解
package com.yuku.yuku_erp.annotation;
import java.lang.annotation.*;
/**
* @author 名一
* @ClassName IdempotentAnnotation
* @description: 用来标记需要校验幂等性的接口
* @datetime 2024年 02月 03日 14:48
* @version: 1.0
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IdempotentAnnotation {
String idempotentType();
}
二:创建一个幂等校验的切面类
package com.yuku.yuku_erp.aop;
import com.yuku.yuku_erp.annotation.IdempotentAnnotation;
import com.yuku.yuku_erp.constant.RedisKeyConstant;
import com.yuku.yuku_erp.exception.MyException;
import com.yuku.yuku_erp.utils.RedisShardedPoolUtil;
import com.yuku.yuku_erp.utils.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @author 名一
* @ClassName CheckIdempotentAop
* @description: 幂等性校验
* @datetime 2024年 02月 03日 14:59
* @version: 1.0
*/
@Slf4j
@Aspect
@Component
public class CheckIdempotentAop {
@Pointcut("execution(* com.yuku.yuku_erp.controller..*.*(..))")
public void checkCut(){
}
@Before("checkCut()")
public void checkIdempotent(JoinPoint joinPoint){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
if (method.isAnnotationPresent(IdempotentAnnotation.class)){
IdempotentAnnotation annotation = method.getAnnotation(IdempotentAnnotation.class);
String idempotentType = annotation.idempotentType();
String idempotentToken = TokenUtil.getRequest().getHeader("idempotentToken");
String idemToken = idempotentType + idempotentToken;
log.info("checkIdempotent idempotentType:{}, idempotentToken:{}", idempotentType, idempotentToken);
Boolean flag = RedisShardedPoolUtil.sismember(RedisKeyConstant.IDEMPOTENT_TOKEN_LIST, idemToken);
if (!flag){
log.error("checkIdempotent error idempotentType:{}, idempotentToken:{}, flag:{}", idempotentType, idempotentToken, flag);
throw new MyException("该接口已提交过,请不要重复提交");
}
RedisShardedPoolUtil.delSetByValue(RedisKeyConstant.IDEMPOTENT_TOKEN_LIST, idemToken);
log.info("checkIdempotent idempotentType:{}, idempotentToken:{}, flag:{}", idempotentType, idempotentToken, flag);
}
}
}
三:在需要切面的接口上使用幂等校验注解
@IdempotentAnnotation(idempotentType = "checkIdempotentToken")
@GetMapping("/checkIdempotentToken")
@ApiOperation(value = "校验幂等性示例")
public CommonResult<String> checkIdempotentToken(){
return CommonResult.success();
}
到此幂等校验就完成了