mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-09 22:45:58 +08:00
fix(transfer): 发起/同步异常错误消息按中文本地化解析后落库, 避免 errorMsg 存 messageKey 字符串
- TransferStartService: 新增 resolveErrorMsg 按 Locale.CHINA 解析 BizException messageKey 后落库; BizException 直接透传保留通道原始 messageKey(由 RestExceptionHandler 按请求 locale 解析), 避免双重前缀 - TransferSyncService: 同步查单失败同样按中文解析错误消息, 避免同步记录存 key
This commit is contained in:
@@ -12,11 +12,13 @@ import cn.daxpay.open.payment.trade.transfer.entity.TransferTrade;
|
||||
import cn.daxpay.open.payment.trade.transfer.param.TransferParam;
|
||||
import cn.daxpay.open.payment.trade.transfer.runtime.mq.TransferSyncMessage;
|
||||
import cn.daxpay.open.platform.common.artemis.service.ArtemisTemplateService;
|
||||
import cn.daxpay.open.platform.common.i18n.util.I18nUtil;
|
||||
import cn.daxpay.open.platform.common.json.util.JacksonUtil;
|
||||
import cn.daxpay.open.platform.common.redis.lock.LockExecutor;
|
||||
import cn.daxpay.open.platform.core.code.CommonCode;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.code.DaxPayErrorCode;
|
||||
import cn.daxpay.open.platform.core.exception.BizException;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -24,6 +26,7 @@ import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -131,11 +134,35 @@ public class TransferStartService {
|
||||
} catch (Exception e) {
|
||||
// 发起异常: 置 FAIL 并记录错误, 然后向上抛出, 避免接口返回"假成功"误导调用方
|
||||
log.error("转账发起失败: tradeNo={}, channel={}", trade.getTradeNo(), channel, e);
|
||||
assistService.fail(channel, trade, e.getMessage());
|
||||
throw new BizInfoException(DaxPayErrorCode.TRADE_FAIL, "pay.error.transfer.createFailed", e.getMessage());
|
||||
// BizException.getMessage() 返回 messageKey(未解析), 需按固定中文解析为本地化文案再落库,
|
||||
// 避免订单 errorMsg 存 key 字符串
|
||||
String errorMsg = resolveErrorMsg(e);
|
||||
assistService.fail(channel, trade, errorMsg);
|
||||
// BizException 直接透传, 保留通道原始 messageKey(由 RestExceptionHandler 按请求 locale 解析),
|
||||
// 避免外层"转账发起失败"与通道前缀叠加成双重前缀; 非 BizException(如网络异常)无 messageKey, 兜底包装
|
||||
if (e instanceof BizException biz) {
|
||||
throw biz;
|
||||
}
|
||||
throw new BizInfoException(DaxPayErrorCode.TRADE_FAIL, "pay.error.transfer.createFailed", errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/// 解析异常为本地化错误消息
|
||||
///
|
||||
/// [BizException] 的 getMessage() 返回 i18n messageKey(未经 I18nUtil 解析), 直接记录会导致订单 errorMsg
|
||||
/// 存 key 字符串(如 "error.channel.alipay.transferFailed")。本方法按固定中文(Locale.CHINA)解析,
|
||||
/// 与 [cn.daxpay.open.platform.system.handler.exception.RestExceptionHandler] 的日志行为一致,
|
||||
/// 保证落库文案不随请求语言变化。非 BizException 的 getMessage() 已是真实文案, 直接使用。
|
||||
private String resolveErrorMsg(Throwable e) {
|
||||
if (e instanceof BizException biz) {
|
||||
String key = biz.resolveMessageKey();
|
||||
if (key != null) {
|
||||
return I18nUtil.get(key, Locale.CHINA, biz.getArgs());
|
||||
}
|
||||
}
|
||||
return e.getMessage();
|
||||
}
|
||||
|
||||
/// 注册 2 分钟延迟同步(发送失败由定时同步任务兜底)
|
||||
private void registerDelaySync(String tradeNo) {
|
||||
try {
|
||||
|
||||
@@ -9,14 +9,17 @@ import cn.daxpay.open.payment.trade.record.entity.PaySyncRecord;
|
||||
import cn.daxpay.open.payment.trade.transfer.bo.TransferResultBo;
|
||||
import cn.daxpay.open.payment.trade.transfer.dao.TransferTradeManager;
|
||||
import cn.daxpay.open.payment.trade.transfer.entity.TransferTrade;
|
||||
import cn.daxpay.open.platform.common.i18n.util.I18nUtil;
|
||||
import cn.daxpay.open.platform.common.redis.lock.LockExecutor;
|
||||
import cn.daxpay.open.platform.core.code.CommonCode;
|
||||
import cn.daxpay.open.platform.core.enums.pay.trade.TradeTypeEnum;
|
||||
import cn.daxpay.open.platform.core.exception.BizException;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
/// # 转账同步服务
|
||||
@@ -76,7 +79,7 @@ public class TransferSyncService {
|
||||
} catch (Exception e) {
|
||||
// 通道查单失败: 保持处理中, 落同步记录, 由定时任务兜底重试
|
||||
log.warn("转账同步查单失败: tradeNo={}, 保持处理中", latestTrade.getTradeNo(), e);
|
||||
this.saveSyncRecord(channel, latestTrade, null, false, e.getMessage());
|
||||
this.saveSyncRecord(channel, latestTrade, null, false, resolveErrorMsg(e));
|
||||
return;
|
||||
}
|
||||
// 按通道结果调整状态
|
||||
@@ -110,4 +113,19 @@ public class TransferSyncService {
|
||||
record.setMchNo(trade.getMchNo());
|
||||
paySyncRecordManager.save(record);
|
||||
}
|
||||
|
||||
/// 解析异常为本地化错误消息
|
||||
///
|
||||
/// [BizException] 的 getMessage() 返回 i18n messageKey(未经 I18nUtil 解析), 直接记录会导致同步记录
|
||||
/// errorMsg 存 key 字符串。本方法按固定中文(Locale.CHINA)解析, 保证落库文案不随请求语言变化。
|
||||
/// 非 BizException 的 getMessage() 已是真实文案, 直接使用。
|
||||
private String resolveErrorMsg(Throwable e) {
|
||||
if (e instanceof BizException biz) {
|
||||
String key = biz.resolveMessageKey();
|
||||
if (key != null) {
|
||||
return I18nUtil.get(key, Locale.CHINA, biz.getArgs());
|
||||
}
|
||||
}
|
||||
return e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user