1、新建注解
/**
* 防止重复提交
*
* @author xxx
* @version 2021/7/10
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatSubmit {
/*** 重复提交,禁止1秒 */
long timeout() default 1000;
/*** 用户openId作为redis键 */
String key() default "";
}
2、使用切面
@Slf4j
@Aspect
@Component
public class RepeatSubmitAspect {
@Autowired
private RedisUtils redisUtils;
/**
* 定义切入点
*/
@Pointcut("@annotation(com.xxx.www.oxxx.order.annotation.RepeatSubmit)")
public void notRepeat() {
}
/**
* 前置通知
*/
/**
* 前置通知
*/
@Before("notRepeat()")
public void before(JoinPoint joinPoint) {
// 接收到请求 记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Assert.notNull(request, "无效请求。");
// 获取全限定类名,日志打印
String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
// 获取注解
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method methodSignature = signature.getMethod();
RepeatSubmit annotation = methodSignature.getAnnotation(RepeatSubmit.class);
//获取注解参数
long timeout = annotation.timeout();
String key = annotation.key();
// 使用el获取opendId
String openId = getOpenId(key, methodSignature, joinPoint.getArgs());
log.warn("========================================== Start ==========================================");
// 打印请求 url
log.warn("URL : {}", request.getRequestURL().toString());
// 打印 Http method
log.warn("HTTP Method : {}", request.getMethod());
// 打印调用全路径以及执行方法
log.warn("Class Method : {}", classMethod);
// 打印请求入参
log.warn("Request Args : 【{}】", JSON.toJSONString(joinPoint.getArgs()));
// 打印返回值
log.debug("========================================== End ==========================================");
String redisKey = new StringBuffer("repeat:").append(classMethod).append(":").append(openId).toString();
log.info("========================================== 防重复提交redis键【{}】 ==========================================", redisKey);
synchronized (redisKey) {
if (redisUtils.exists(redisKey)) {
log.warn("无效重复提交key:{}", redisKey);
throw new BusinessException("不可重复提交。");
} else {
redisUtils.set(redisKey, openId, timeout);
}
}
}
/**
* 通过el表达式获取用户id
*
* @param key
* @param method
* @param args
* @return
*/
private String getOpenId(String key, Method method, Object[] args) {
LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
String[] paraNameArr = discoverer.getParameterNames(method);
StandardEvaluationContext context = new StandardEvaluationContext();
for (int i = 0; i < paraNameArr.length; i++) {
context.setVariable(paraNameArr[i], args[i]);
}
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(key);
String returnVal = expression.getValue(context, String.class);
return returnVal == null ? "" : returnVal;
}
}
3、使用注解
/**
* 订单下单
*
* @param orderInfoDTO
* @return
* @throws WxPayException
*/
@PostMapping("/addOrder")
@RepeatSubmit(key = "#orderInfoDTO.openId", timeout = 1)
@ApiOperationSupport(order = 8)
@ApiOperation(value = "订单下单", notes = "商品名称,商品金额")
public R<String> payOrder(@ApiParam(value = "主键集合", required = true) @RequestBody OrderInfoDTO orderInfoDTO) throws WxPayException {
R<String> stringR = orderInfoService.payOrder(orderInfoDTO);
return stringR;
}