预存支付订单逻辑梳理

Created at 2020-02-17 Updated at 2020-07-29 Category 项目 Tag 设计模式 / redisson / 分布式

用户需要预存金额才可以用于消费,会员到期后自动退还剩余预存余额。预存的金额可用于购买好友推荐、地区筛选、信用报告等服务,由于运存支付的流程顺序不会变,但是每一项购买的具体内容是不一样的,所以预存支付可利用模板方法模式来完成。

模板方法模式

模板方法定义了某特定算法如何执行的框架,但执行步骤的具体实现则推迟到子类中去完成。

预存支付模板方法核心代码

private Result<PreStoredPreOrderPreHandlerResult> routingAndDoPreHandle(@NonNull PreStoredTransactionPreOrderRequestDTO request, @NonNull PreStoredHandlerStateStorage stateStorage) {
    //得到相应的订单类型
    PreStoredPreOrderPreHandler handler = this.handlerMap.get(request.getPreStoredOrderType());
    if (Objects.isNull(handler)) {
        log.error("未找到可以处理该预存预下单请求的预处理器-handlerSize=[{}]-request={}", this.handlerMap.size(), JSON.toJSONString(request));
        return ResultUtil.defaultFailure(ERspCode.FAILURE);
    }
    log.info("选择并执行适合的预存支付预下单预处理器-handlerName=[{}]", handler.getHandlerName());
    // 执行前置处理
    Result beforeHandleResult = handler.beforeHandle(request, stateStorage);
    if (!ResultUtil.checkSuccess(beforeHandleResult)) {
        log.error("选择并执行适合的预存支付预下单预处理器失败-前置处理器处理失败-handler={}-result={}", handler.getHandlerName(), JSON.toJSONString(beforeHandleResult));
        return ResultUtil.defaultFailure(beforeHandleResult.getError());
    }
    // 执行预下单预处理器
    Result<PreStoredPreOrderPreHandlerResult> result = handler.doPreHandle(request, stateStorage);
    if (!ResultUtil.checkSuccess(result)) {
        log.error("选择并执行适合的预存支付预下单预处理器失败-预处理器处理失败-handler={}-result={}", handler.getHandlerName(), JSON.toJSONString(result));
        return result;
    }
    // 预处理器处理结果校验
    Result<PreStoredPreOrderPreHandlerResult> checkPreHandleResult = this.checkPreHandleResult(handler, result.getData());
    if (!ResultUtil.checkSuccess(checkPreHandleResult)) {
        log.error("预下单预处理器执行结果校验失败-handler={}-result={}", handler.getHandlerName(), JSON.toJSONString(checkPreHandleResult));
        return ResultUtil.defaultFailure(ERspCode.FAILURE);
    }
    return result;
}

上面代码中PreStoredPreOrderPreHandler handler = this.handlerMap.get(request.getPreStoredOrderType());使用工厂模式的到相应订单类型,beforeHandledoPreHandle是需要不同子类实现的方法。

工厂模式

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

redisson 分布式锁

防止多次支付,保证幂等性。

  1. 在 PreStoredPreOrderInvoker 中使用 Redisson 加锁。
// 生成锁名称
final String lockName = String.format(PRE_ORDER_LOCK_NAME_TEMP, request.getMemberId(), request.getPreStoredOrderType().getType());

// 获取锁
RLock lock = redisLock.getRLock(lockName);

try {
    // 尝试加锁,处理加锁失败场景。
    if (!lock.tryLock(5, 15, TimeUnit.SECONDS)) {
        log.info("执行预存预下单处理加锁失败-存在同会员同类型正在处理的预下单请求-request={}", JSON.toJSONString(request));
        return ResultUtil.defaultFailure(ERspCode.FAILURE, "下单请求正在处理");
    }

    // 执行预下单处理
    result = this.invokePreStore(request);
} catch (Exception e) {
    log.error("预存支付预下单失败", e);
    return ResultUtil.defaultFailure(ERspCode.FAILURE);
} finally {
    lock.unlock();
}

invokePreStore 执行预下单

// 状态存储:在处理器方法调用链中实现数据流转
PreStoredHandlerStateStorage stateStorage = new PreStoredHandlerStateStorage(memberInfo);

// 选择并执行适合的预存支付预下单预处理器
Result<PreStoredPreOrderPreHandlerResult> routingBeforeHandlerAndDoResult = this.routingAndDoPreHandl(request, stateStorage);
if (!ResultUtil.checkSuccess(routingBeforeHandlerAndDoResult)) {
    return ResultUtil.defaultFailure(routingBeforeHandlerAndDoResult.getError());
}

// 预下单
return this.preStoredPreOrder(request, routingBeforeHandlerAndDoResult.getData());

AbstractPreStoredProcessor

抽象预存支付处理器,提供预存预下单、预存订单支付一些标准方法和配置

  • 会员权限校验
  • 获取地区筛选服务配置
  • 获取日料配置

PreStoredPreOrderPreHandler

/**
 * 获取预存预下单处理器名称
 *
 * @return 预存预下单处理器名称
 */
String getHandlerName();
/**
 * 获取预存预下单处理器可处理的预下单订单类型
 *
 * @return 预下单订单类型
 */
EPreStoredOrderType getCanHandleOrderType();
/**
 * 前置处理器
 *
 * @param request 预下单请求对象
 * @param stateStorage 状态存储
 * @return 处理结果
 * @author Thankson
 * @date 2019-10-31 13:05
 */
Result beforeHandle(@NonNull PreStoredTransactionPreOrderRequestDTO request, @NonNull PreStoredHandlerStateStoragestateStorage);
/**
 * 预下单预处理器,用于在落单前计算需支付的订单价格等
 *
 * @param request 预下单请求对象
 * @param stateStorage 状态存储
 * @return 预处理器处理结果
 * @author Thankson
 * @date 2019-10-31 13:06
 */
Result<PreStoredPreOrderPreHandlerResult> doPreHandle(@NonNull PreStoredTransactionPreOrderRequestDTO request,@NonNull PreStoredHandlerStateStorage stateStorage);

BasePreStoredPreOrderPreHandler

抽象预存预下单处理器

public abstract class BasePreStoredPreOrderPreHandler extends AbstractPreStoredProcessor implements PreStoredPreOrderPreHandler
Site by Cellophane using Hexo & Random

Hide