拼多多消息对接、支付服务策略(策略+工厂)

一、拼多多消息对接

 
策略抽象接口


/**
 * 策略抽象接口
 *
 * @author zj
 * @date 2023/5/23 17:03
 */
public interface AbstractStrategy<T, R> {

    /**
     * 策略标识
     *
     * @return 策略标识
     */
    String strategyCode();

    /**
     * 执行策略
     *
     * @param t 策略入参
     */
    default void execute(T t) {
    }

    /**
     * 执行策略,带返回值
     *
     * @param t 策略入参
     * @return 策略后返回值
     */
    default R executeResp(T t) {
        return null;
    }
}

策略工厂抽象接口


/**
 * 抽象策略工厂
 *
 * @author zj
 * @date 2023/5/23 17:03
 */
@Component
public class AbstractStrategyFactory<T, R> implements CommandLineRunner {

    /**
     * 策略集合
     */
    private final Map<String, AbstractStrategy<T, R>> abstractStrategyHashMap = MapUtil.newHashMap();

    /**
     * 根据 strategyCode 获取具体策略
     *
     * @param strategyCode 策略标识
     * @return 实际执行策略
     */
    public AbstractStrategy<T, R> get(String strategyCode) {
        return Optional.ofNullable(abstractStrategyHashMap.get(strategyCode)).orElseThrow(() -> new RuntimeException(String.format("%s 策略未定义", strategyCode)));
    }

    /**
     * 根据 strategyCode 查询具体策略并执行
     *
     * @param strategyCode 策略标识
     * @param t    策略入参
     */
    public void execute(String strategyCode, T t) {
        AbstractStrategy<T, R> strategy = get(strategyCode);
        strategy.execute(t);
    }

    /**
     * 根据 strategyCode 查询具体策略并执行,带返回结果
     *
     * @param strategyCode 策略标识
     * @param t    策略入参
     * @return {@link R}
     */
    public R executeResp(String strategyCode, T t) {
        AbstractStrategy<T, R> strategy = get(strategyCode);
        return strategy.executeResp(t);
    }

    @Override
    @SuppressWarnings({"unchecked", "rawtypes"})
    public void run(String... args) {
        Map<String, AbstractStrategy> strategyMap = SpringUtil.getBeansOfType(AbstractStrategy.class);
        strategyMap.forEach((beanName, bean) -> {
            if (abstractStrategyHashMap.containsKey(bean.strategyCode())) {
                throw new RuntimeException(String.format("%s duplicate execution policy", bean.strategyCode()));
            }
            abstractStrategyHashMap.put(bean.strategyCode(), (AbstractStrategy<T, R>)bean);
        });
    }

 拼多多消息策略处理接口

/**
 * 拼多多消息处理策略
 *
 * @author zj
 * @date 2023/02/27
 */
public interface PddMessageStrategy extends AbstractStrategy<PopMessage, PopMessageAck> {

}

拼多多消息策略工厂

/**
 * pdd消息策略工厂
 *
 * @author zj
 * @date 2023/03/01
 */
@RequiredArgsConstructor
@Component
public class PddMessageStrategyFactory {

    /**
     * 抽象战略工厂
     */
    private final AbstractStrategyFactory<PopMessage, PopMessageAck> abstractStrategyFactory;

    /**
     * 获取
     *
     * @param strategyCode 标记
     * @return {@link PddMessageStrategy}
     */
    public PddMessageStrategy get(String strategyCode) {
        return (PddMessageStrategy) abstractStrategyFactory.get(strategyCode);
    }


    /**
     * 执行响应
     *
     * @param strategyCode 策略编号
     * @param popMessage   拼多多消息
     * @return {@link PopMessageAck}
     */
    public PopMessageAck executeResp(String strategyCode, PopMessage popMessage) {
        return get(strategyCode).executeResp(popMessage);
    }
}

 消息统一处理(先落表再执行,异常时补偿)


/**
 * 拼多多消息处理器
 * 
 * 只关注业务处理,ACK、重连、异常SDK内部处理
 *
 * @author zj
 * @date 2023/03/01
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class PddMessageHandler implements MessageHandler {

    /**
     * mq服务
     */
    private final MqService mqService;

    /**
     * pdd消息策略工厂
     */
    private final PddMessageStrategyFactory pddMessageStrategyFactory;

    @Override
    public void onMessage(Message message) {
        // 业务处理逻辑
        log.info("收到拼多多消息: {}", message);
        MessageLogCreateListener.CreateMessage createMessage = new MessageLogCreateListener.CreateMessage();
        createMessage.setTopic(message.getType());
        createMessage.setEvent(message.getType());
        createMessage.setMark(StrUtil.toString(message.getMallID()));
        createMessage.setMsgBody(message.getContent());
        MessageAck messageAck = mqService.publish(MessageLogCreateListener.wrapper(createMessage));
        log.info("[onMessage][messageAck({})]", messageAck);

        PddMessageTypeEnum enumByCode = EnumUtil.getEnumByCode(PddMessageTypeEnum.class, message.getType());
        AssertUtil.notNull(enumByCode);
        PopMessageAck popMessageAck = pddMessageStrategyFactory.executeResp(enumByCode.getCode(), this.convertToPopMessage(message));
        AssertUtil.isTrue(popMessageAck.isSuccess());
    }

    /**
     * 转换为拼多多消息
     *
     * @param message 消息
     * @return {@link PopMessage}
     */
    public PopMessage convertToPopMessage(Message message) {
        PopMessage popMessage = new PopMessage();
        popMessage.setType(message.getType());
        popMessage.setContent(message.getContent());
        popMessage.setMallId(message.getMallID());
        return popMessage;
    }
}

 拼多多交易成功处消息实现(其他消息同理)

/**
 * 交易成功 消息策略
 *
 * @author zj
 * @date 2023/02/27
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class TradeSuccessMessageStrategy implements PddMessageStrategy {

    /**
     * 订单信息服务
     */
    private final OrderInfoService orderInfoService;

    @Override
    public String strategyCode() {
        return PddMessageTypeEnum.TRADE_SUCCESS.getCode();
    }

    @Override
    public PopMessageAck executeResp(PopMessage popMessage) {
        log.info("处理【交易成功】消息: {}", popMessage);
        orderInfoService.updateStatus(this.convertToOrderInfoUpdateStatusRequest(popMessage));
        return PopMessageAck.success();
    }

策略消息枚举


/**
 * 拼多多消息type枚举
 * 
 * @author zj
 * @date 2023-02-26
 */
@Getter
@AllArgsConstructor
public enum PddMessageTypeEnum implements EnumCode<String> {

    /**
     * 交易成功消息
     */
    TRADE_SUCCESS("pdd_trade_TradeSuccess", "交易成功消息"),

    /**
     * 卖家发货消息
     */
    TRADE_SELLER_SHIP("pdd_trade_TradeSellerShip", "卖家发货消息"),

    /**
     * 交易确认消息
     */
    TRADE_CONFIRMED("pdd_trade_TradeConfirmed", "交易确认消息"),

    /**
     * 同意退款协议消息
     */
    REFUND_AGREE_AGREEMENT("pdd_refund_RefundAgreeAgreement", "同意退款协议消息"),

    /**
     * 售后单关闭消息
     */
    REFUND_CLOSED("pdd_refund_RefundClosed", "售后单关闭消息");

    /**
     * 消息Topic编码
     */
    private final String code;

    /**
     * 消息Topic描述
     */
    private final String message;
}

二、简单支付服务策略

抽象策略工厂、抽象策略同上,支付服务策略封装常用支付方法,出入参抽取通用支付属性,根据所需业务自行扩展,如下

/**
 * 支付服务策略
 *
 * @author zj
 * @date 2023/8/26 10:01
 */
public interface PayStrategyService extends AbstractStrategy<Void, Void> {

    /**
     * 获取支付链接
     *
     * @param dto dto
     * @return str
     */
    Object payment(PaymentInputDto dto);

    /**
     * 查询支付结果
     *
     * @param dto dto
     * @return obj
     */
    default PaymentQueryOutputDto queryPayResult(PaymentQueryInputDto dto) {
        throw ServiceException("不支持该方式");
    }

    /**
     * 解析支付结果
     *
     * @param data object data
     * @return obj
     */
    default Object parseOrderNotifyResult(Object data) {
        throw ServiceException("不支持该方式");
    }

    /**
     * 解析退款结果
     *
     * @param data data
     * @return obj
     */
    default Object parseRefundNotifyResult(Object data) {
        throw ServiceException("不支持该方式");
    }

    /**
     * 解析确认收货结果
     *
     * @param data 数据
     * @return {@link Object}
     */
    default Object parseConfirmNotifyResult(Object data) {
        throw ServiceException("不支持该方式");
    }

    /**
     * 退款
     *
     * @param dto dto
     */
    void refund(RefundInputDto dto);

    /**
     * 转账
     *
     * @param dto dto
     * @return object
     */
    default PartnerTransferResult transfer(TransferInputDto dto) {
        throw ServiceException("不支持该方式");
    }

 策略实现(余额支付、微信支付、聚富通支付等等实现支付策略,未实现方法以“不支持该方式”进行异常抛出)

@Service
@RequiredArgsConstructor
public class BalancePayStrategyServiceImpl implements PayStrategyService {

    /**
     * 订单服务
     */
    private final OrdersService orderService;

    /**
     * 平衡服务
     */
    private final BalanceService balanceService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object payment(PaymentInputDto dto) {
        Long userId = MapUtil.getLong(dto.getParamsMap(), "userId");
        OrderVO orderVO = this.orderService.payOrderCheck(dto.getOrderNo(), userId);
        BalanceSubtractInputDto balanceSubtract = new BalanceSubtractInputDto();
        balanceSubtract.setSubtractType(BalanceSubtract.ORDER_DEDUCTION.getValue());
        balanceSubtract.setUserId(userId);
        balanceSubtract.setBalance(orderVO.getPayAmount());
        balanceSubtract.setDescription("下单使用余额抵扣" + orderVO.getPayAmount() + "元");
        balanceSubtract.setRelNo(dto.getOrderNo());
        balanceSubtract.setSource(BalanceSource.ORDER_DEDUCTION.getValue());
        this.balanceService.subtract(balanceSubtract);

        orderVO.setPaidAmount(orderVO.getPayAmount());
        orderVO.setPayType(PayType.Balance.getValue());
        orderVO.setTransactionId(
                DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN) + RandomUtil.randomNumbers(4));
        this.orderService.updateForPaySuccess(orderVO);
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refund(RefundInputDto dto) {
        BalancePlusInputDto plusInputDto = new BalancePlusInputDto();
        plusInputDto.setPlusType(BalancePlus.ORDER_BACKOFF.getValue());
        plusInputDto.setBalance(dto.getRefundFee());
        plusInputDto.setRelNo(dto.getOutRefundNo());
        plusInputDto.setUserId(MapUtil.getLong(dto.getParamsMap(), "userId"));
        plusInputDto.setSource(BalanceSource.ORDER_COMPENSATE.getValue());
        plusInputDto.setDescription("订单售后补偿,退回" + dto.getRefundFee() + "元");
        this.balanceService.plus(plusInputDto);
        if (ObjectUtil.isNotNull(dto.getSuccessCallback())) {
            dto.getSuccessCallback().run();
        }
    }

    @Override
    public String mark() {
        return PayType.Balance.getPayChannelStrategyKey();
    }
}

支付策略调用

@ApiOperation("H5待支付订单获取支付参数")
    @GetMapping("pay/h5/{orderNo}")
    public JsonResult<OrderPayDTO> payOrderOfH5(@PathVariable("orderNo") String orderNo) {
        return orderService.payOrder(orderNo, TradeType.MWEB.name(), PayType.Wechat.getValue());
    }

    /**
     * 支付订单
     *
     * @param orderNo   订单号
     * @param tradeType 交易类型
     * @param payType   支付类型
     * @return {@link JsonResult}<{@link OrderPayDTO}>
     */
    @Override
    public JsonResult<OrderPayDTO> payOrder(String orderNo, String tradeType, Integer payType) {
        AssertUtil.notNull(payType, "支付方式不能为空");
        AssertUtil.isTrue(PayType.exist(payType), "错误的支付类型");
        AssertUtil.isTrue(TradeType.exist(tradeType), "错误的交易类型");
        OrderVO orderVO = this.orderService.payOrderCheck(orderNo, this.teancyUser.getUserId());
        if (this.payProperties.getTest()) {
            orderVO.setTransactionId(orderNo);
            orderVO.setPayType(payType);
            this.orderService.updateForPaySuccess(orderVO);
            return JsonResult.ok();
        }
        String openId = MapUtil.getStr(this.teancyUser.getExtendInfo(), "openId");
        Object payment = ((PayStrategyService) this.abstractStrategyFactory
                .get(PayType.getInstance(payType).getPayChannelStrategyKey()))
                .payment(new PaymentInputDto()
                        .setOrderNo(orderNo)
                        .setPayAmount(orderVO.getPayAmount())
                        .setDescription("普通订单")
                        .setNotifyUrl(this.payProperties.getPayNotifyUrl())
                        .setTradeType(tradeType)
                        .setUserId(openId)
                );
        OrderPayDTO orderPayDTO = new OrderPayDTO();
        orderPayDTO.setPayParam(payment);
        return JsonResult.ok(orderPayDTO);
    }

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值