一、拼多多消息对接
策略抽象接口
/**
* 策略抽象接口
*
* @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);
}
1086

被折叠的 条评论
为什么被折叠?



