后端使用注解防重复提交

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 payOrder(@ApiParam(value = "主键集合", required = true) @RequestBody OrderInfoDTO orderInfoDTO) throws WxPayException {
		R stringR = orderInfoService.payOrder(orderInfoDTO);
		return stringR;
	}

你可能感兴趣的:(防重复提交)