新建注解
@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiIdempotent {
String type() default "head";
}
新建注解切面
@Aspect
@Component
public class ApiIdempotentAspect {
@Autowired
private RedisUtils redisUtils;
@Autowired
private BaseConstant baseConstant;
@Pointcut("@annotation(com.exing.annotation.ApiIdempotent)")
public void ApiIdempotent() {
}
// 环绕通知验证参数
@Around("ApiIdempotent()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
ApiIdempotent apiIdempotent = signature.getMethod().getDeclaredAnnotation(ApiIdempotent.class);
if (apiIdempotent != null) {
return apiIdempotent(proceedingJoinPoint, signature);
}
// 放行
Object proceed = proceedingJoinPoint.proceed();
return proceed;
}
// 验证Token
public Object apiIdempotent(ProceedingJoinPoint proceedingJoinPoint, MethodSignature signature)
throws Throwable {
ApiIdempotent apiIdempotent = signature.getMethod().getDeclaredAnnotation(ApiIdempotent.class);
if (apiIdempotent == null) {
// 直接执行程序
Object proceed = proceedingJoinPoint.proceed();
return proceed;
}
// 代码步骤:
// 1.获取令牌 存放在请求头中
HttpServletRequest request = getRequest();
String valueType = apiIdempotent.type();
if (StringUtils.isEmpty(valueType)) {
throw new BadRequestException("注解参数错误!");
}
String token = null;
if (valueType.equals("head")) {
token = request.getHeader("token");
} else {
token = request.getParameter("token");
}
if (StringUtils.isEmpty(token)) {
throw new BadRequestException("缺少幂等性校验token!");
}
if (Objects.isNull(redisUtils.get(baseConstant.getIdempotentKey().concat(token)))) {
throw new BadRequestException("请勿重复提交!");
}
Object proceed = proceedingJoinPoint.proceed();
redisUtils.del(baseConstant.getIdempotentKey().concat(token));
return proceed;
}
public HttpServletRequest getRequest() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
return request;
}
}
获取幂等性token 放在接口请求的header里面 key为token
@ApiOperation(value = "幂等性验证token", response = String.class)
@GetMapping("/getToken")
@ApiLog("幂等性验证token")
@AnonymousAccess
public ResponseEntity getToken(HttpServletRequest request) {
String token = UUID.randomUUID().toString();
redisUtils.set(baseConstant.getIdempotentKey().concat(token), token, 30000);
request.setAttribute("token", token);
return new ResponseEntity(token, HttpStatus.OK);
}
测试
@ApiIdempotent
public ResponseEntity createOrder(@Validated(SaveApplyCarReqDto.Create.class) @RequestBody SaveApplyCarReqDto reqDto) {
orderService.createOrder(reqDto);
return new ResponseEntity(HttpStatus.OK);
}