mall + pay:调整异常的处理

1. 如果是业务异常,则统一转换成 ServiceException
2. 如果是系统异常,则使用 PayException 包装成无需 check 的异常
This commit is contained in:
YunaiV 2023-07-08 19:26:42 +08:00
parent e615be971e
commit efb221b1fe
13 changed files with 133 additions and 102 deletions

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.common.exception.util;
import cn.iocoder.yudao.framework.common.exception.ErrorCode; import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -80,6 +81,10 @@ public class ServiceExceptionUtil {
return new ServiceException(code, message); return new ServiceException(code, message);
} }
public static ServiceException invalidParamException(String messagePattern, Object... params) {
return exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), messagePattern, params);
}
// ========== 格式化方法 ========== // ========== 格式化方法 ==========
/** /**

View File

@ -1,26 +1,17 @@
package cn.iocoder.yudao.framework.pay.core.client.exception; package cn.iocoder.yudao.framework.pay.core.client.exception;
import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/** /**
* 业务逻辑异常 Exception * 支付系统异常 Exception
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class PayException extends RuntimeException { public class PayException extends RuntimeException {
/** public PayException(Throwable cause) {
* 第三方平台的错误码 super(cause);
*/ }
private String code;
/**
* 第三方平台的错误提示
*/
private String message;
} }

View File

@ -1,24 +1,19 @@
package cn.iocoder.yudao.framework.pay.core.client.impl; package cn.iocoder.yudao.framework.pay.core.client.impl;
import cn.hutool.core.date.LocalDateTimeUtil; import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.pay.core.client.PayClient; import cn.iocoder.yudao.framework.pay.core.client.PayClient;
import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO;
import com.alipay.api.AlipayResponse; import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import javax.validation.Validation; import javax.validation.Validation;
import java.time.LocalDateTime;
import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.framework.pay.core.enums.PayFrameworkErrorCodeConstants.PAY_EXCEPTION;
// TODO 芋艿优化下替换异常
/** /**
* 支付客户端的抽象类提供模板方法减少子类的冗余代码 * 支付客户端的抽象类提供模板方法减少子类的冗余代码
* *
@ -78,16 +73,19 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
@Override @Override
public final PayOrderUnifiedRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { public final PayOrderUnifiedRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
Validation.buildDefaultValidatorFactory().getValidator().validate(reqDTO); Validation.buildDefaultValidatorFactory().getValidator().validate(reqDTO);
// 执行短信发送 // 执行统一下单
PayOrderUnifiedRespDTO result; PayOrderUnifiedRespDTO resp;
try { try {
result = doUnifiedOrder(reqDTO); resp = doUnifiedOrder(reqDTO);
} catch (ServiceException ex) {
// 业务异常都是实现类已经翻译所以直接抛出即可
throw ex;
} catch (Throwable ex) { } catch (Throwable ex) {
// 打印异常日志 // 系统异常则包装成 PayException 异常抛出
log.error("[unifiedOrder][request({}) 发起支付失败]", toJsonString(reqDTO), ex); log.error("[unifiedRefund][request({}) 发起支付异常]", toJsonString(reqDTO), ex);
throw buildException(ex); throw buildException(ex);
} }
return result; return resp;
} }
protected abstract PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) protected abstract PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO)
@ -95,12 +93,17 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
@Override @Override
public PayRefundUnifiedRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO) { public PayRefundUnifiedRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
Validation.buildDefaultValidatorFactory().getValidator().validate(reqDTO);
// 执行统一退款
PayRefundUnifiedRespDTO resp; PayRefundUnifiedRespDTO resp;
try { try {
resp = doUnifiedRefund(reqDTO); resp = doUnifiedRefund(reqDTO);
} catch (Throwable ex) { } catch (ServiceException ex) {
// 记录异常日志 // 业务异常都是实现类已经翻译所以直接抛出即可
log.error("[unifiedRefund][request({}) 发起退款失败]", toJsonString(reqDTO), ex); throw ex;
} catch (Throwable ex) {
// 系统异常则包装成 PayException 异常抛出
log.error("[unifiedRefund][request({}) 发起退款异常]", toJsonString(reqDTO), ex);
throw buildException(ex); throw buildException(ex);
} }
return resp; return resp;
@ -110,32 +113,11 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
// ========== 各种工具方法 ========== // ========== 各种工具方法 ==========
private RuntimeException buildException(Throwable ex) { private PayException buildException(Throwable ex) {
if (ex instanceof RuntimeException) { if (ex instanceof PayException) {
return (RuntimeException) ex; return (PayException) ex;
} }
throw new RuntimeException(ex); throw new PayException(ex);
}
protected void validateSuccess(AlipayResponse response) {
if (response.isSuccess()) {
return;
}
throw exception0(PAY_EXCEPTION.getCode(), response.getSubMsg());
}
protected String formatAmount(Integer amount) {
return String.valueOf(amount / 100.0);
}
protected String formatTime(LocalDateTime time) {
// "yyyy-MM-dd HH:mm:ss"
return LocalDateTimeUtil.format(time, NORM_DATETIME_FORMATTER);
}
protected LocalDateTime parseTime(String str) {
// "yyyy-MM-dd HH:mm:ss"
return LocalDateTimeUtil.parse(str, NORM_DATETIME_FORMATTER);
} }
} }

View File

@ -1,7 +1,9 @@
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO;
@ -9,9 +11,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReq
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum; import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum;
import com.alipay.api.AlipayApiException; import com.alipay.api.*;
import com.alipay.api.AlipayConfig;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeRefundModel; import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.internal.util.AlipaySignature; import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeRefundRequest; import com.alipay.api.request.AlipayTradeRefundRequest;
@ -20,9 +20,13 @@ import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Map; import java.util.Map;
import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.framework.pay.core.enums.PayFrameworkErrorCodeConstants.ORDER_UNIFIED_ERROR;
/** /**
* 支付宝抽象类实现支付宝统一的接口以及部分实现退款 * 支付宝抽象类实现支付宝统一的接口以及部分实现退款
@ -58,7 +62,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
model.setOutTradeNo(reqDTO.getPayTradeNo()); model.setOutTradeNo(reqDTO.getPayTradeNo());
model.setOutRequestNo(reqDTO.getMerchantRefundId()); model.setOutRequestNo(reqDTO.getMerchantRefundId());
model.setRefundAmount(formatAmount(reqDTO.getAmount()).toString()); model.setRefundAmount(formatAmount(reqDTO.getAmount()));
model.setRefundReason(reqDTO.getReason()); model.setRefundReason(reqDTO.getReason());
AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest(); AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest();
@ -114,4 +118,35 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
.build(); .build();
} }
// ========== 各种工具方法 ==========
protected String formatAmount(Integer amount) {
return String.valueOf(amount / 100.0);
}
protected String formatTime(LocalDateTime time) {
return LocalDateTimeUtil.format(time, NORM_DATETIME_FORMATTER);
}
protected LocalDateTime parseTime(String str) {
return LocalDateTimeUtil.parse(str, NORM_DATETIME_FORMATTER);
}
/**
* 校验支付宝统一下单的响应
*
* 如果校验不通过则抛出 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 异常
*
* @param request 请求
* @param response 响应
*/
protected void validateUnifiedOrderResponse(Object request, AlipayResponse response) {
if (response.isSuccess()) {
return;
}
log.error("[validateUnifiedOrderResponse][发起支付失败request({})response({})]",
JsonUtils.toJsonString(request), JsonUtils.toJsonString(response));
throw exception0(ORDER_UNIFIED_ERROR.getCode(), response.getSubMsg());
}
} }

View File

@ -49,7 +49,7 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient {
// 2.1 执行请求 // 2.1 执行请求
AlipayTradeAppPayResponse response = client.execute(request); AlipayTradeAppPayResponse response = client.execute(request);
// 2.2 处理结果 // 2.2 处理结果
validateSuccess(response); validateUnifiedOrderResponse(request, response);
return new PayOrderUnifiedRespDTO() return new PayOrderUnifiedRespDTO()
.setDisplayMode(displayMode).setDisplayContent(""); .setDisplayMode(displayMode).setDisplayContent("");
} }

View File

@ -13,7 +13,6 @@ import com.alipay.api.response.AlipayTradePayResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
/** /**
@ -59,8 +58,9 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient {
// 2.1 执行请求 // 2.1 执行请求
AlipayTradePayResponse response = client.execute(request); AlipayTradePayResponse response = client.execute(request);
// 2.2 处理结果 // 2.2 处理结果
validateSuccess(response); validateUnifiedOrderResponse(request, response);
return new PayOrderUnifiedRespDTO() return new PayOrderUnifiedRespDTO()
.setDisplayMode(displayMode).setDisplayContent(""); .setDisplayMode(displayMode).setDisplayContent("");
} }
} }

View File

@ -59,9 +59,8 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient {
} else { } else {
response = client.pageExecute(request, Method.GET.name()); response = client.pageExecute(request, Method.GET.name());
} }
// 2.2 处理结果 // 2.2 处理结果
validateSuccess(response); validateUnifiedOrderResponse(request, response);
return new PayOrderUnifiedRespDTO().setDisplayMode(displayMode) return new PayOrderUnifiedRespDTO().setDisplayMode(displayMode)
.setDisplayContent(response.getBody()); .setDisplayContent(response.getBody());
} }

View File

@ -47,7 +47,7 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient {
// 2.1 执行请求 // 2.1 执行请求
AlipayTradePrecreateResponse response = client.execute(request); AlipayTradePrecreateResponse response = client.execute(request);
// 2.2 处理结果 // 2.2 处理结果
validateSuccess(response); validateUnifiedOrderResponse(request, response);
return new PayOrderUnifiedRespDTO() return new PayOrderUnifiedRespDTO()
.setDisplayMode(displayMode).setDisplayContent(response.getQrCode()); .setDisplayMode(displayMode).setDisplayContent(response.getQrCode());
} }

View File

@ -50,7 +50,7 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient {
AlipayTradeWapPayResponse response = client.pageExecute(request, Method.GET.name()); AlipayTradeWapPayResponse response = client.pageExecute(request, Method.GET.name());
// 2.2 处理结果 // 2.2 处理结果
validateSuccess(response); validateUnifiedOrderResponse(request, response);
return new PayOrderUnifiedRespDTO() return new PayOrderUnifiedRespDTO()
.setDisplayMode(displayMode).setDisplayContent(response.getBody()); .setDisplayMode(displayMode).setDisplayContent(response.getBody());
} }

View File

@ -4,16 +4,14 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.date.TemporalAccessorUtil; import cn.hutool.core.date.TemporalAccessorUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.io.FileUtils; import cn.iocoder.yudao.framework.common.util.io.FileUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
import cn.iocoder.yudao.framework.pay.core.enums.PayFrameworkErrorCodeConstants;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result;
import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.config.WxPayConfig;
@ -26,6 +24,9 @@ import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.util.Objects; import java.util.Objects;
import static cn.hutool.core.date.DatePattern.PURE_DATETIME_PATTERN;
import static cn.hutool.core.date.DatePattern.UTC_WITH_XXX_OFFSET_PATTERN;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.*;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
/** /**
@ -67,8 +68,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
} }
@Override @Override
protected PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) protected PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws Exception {
throws Throwable {
try { try {
switch (config.getApiVersion()) { switch (config.getApiVersion()) {
case WxPayClientConfig.API_VERSION_V2: case WxPayClientConfig.API_VERSION_V2:
@ -79,8 +79,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
} }
} catch (WxPayException e) { } catch (WxPayException e) {
log.error("[doUnifiedOrder][request({}) 发起支付失败]", toJsonString(reqDTO), e); throw buildUnifiedOrderException(reqDTO, e);
throw buildPayException(e);
} }
} }
@ -118,7 +117,9 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
} }
} catch (WxPayException e) { } catch (WxPayException e) {
log.error("[parseNotify][rawNotify({}) 解析失败]", toJsonString(rawNotify), e); log.error("[parseNotify][rawNotify({}) 解析失败]", toJsonString(rawNotify), e);
throw buildPayException(e); // throw buildPayException(e);
throw new RuntimeException(e);
// TODO 芋艿缺一个异常翻译
} }
} }
@ -151,33 +152,47 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
// ========== 各种工具方法 ========== // ========== 各种工具方法 ==========
static String getOpenid(PayOrderUnifiedReqDTO reqDTO) { /**
String openid = MapUtil.getStr(reqDTO.getChannelExtras(), "openid"); * 构建统一下单的异常
if (StrUtil.isEmpty(openid)) { *
throw new IllegalArgumentException("支付请求的 openid 不能为空!"); * 目的将参数不正确等异常转换成 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 业务异常
*
* @param reqDTO 请求
* @param e 微信的支付异常
* @return 转换后的异常
*
*/
static Exception buildUnifiedOrderException(PayOrderUnifiedReqDTO reqDTO, WxPayException e) {
// 情况一业务结果为 FAIL
if (Objects.equals(e.getResultCode(), "FAIL")) {
log.error("[buildUnifiedOrderException][request({}) 发起支付失败]", toJsonString(reqDTO), e);
if (Objects.equals(e.getErrCode(), "PARAM_ERROR")) {
throw invalidParamException(e.getErrCodeDes());
}
throw exception(PayFrameworkErrorCodeConstants.ORDER_UNIFIED_ERROR, e.getReturnMsg());
} }
return openid; // 情况二状态码结果为 FAIL
} if (Objects.equals(e.getReturnCode(), "FAIL")) {
throw exception(PayFrameworkErrorCodeConstants.ORDER_UNIFIED_ERROR, e.getReturnMsg());
static PayException buildPayException(WxPayException e) { }
return new PayException(ObjectUtils.defaultIfNull(e.getErrCode(), e.getReturnCode()), // 情况三系统异常这里暂时不打交给上层的 AbstractPayClient 统一打
ObjectUtils.defaultIfNull(e.getErrCodeDes(), e.getCustomErrorMsg())); return e;
} }
static String formatDateV2(LocalDateTime time) { static String formatDateV2(LocalDateTime time) {
return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), "yyyyMMddHHmmss"); return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), PURE_DATETIME_PATTERN);
} }
static LocalDateTime parseDateV2(String time) { static LocalDateTime parseDateV2(String time) {
return LocalDateTimeUtil.parse(time, "yyyyMMddHHmmss"); return LocalDateTimeUtil.parse(time, PURE_DATETIME_PATTERN);
} }
static String formatDateV3(LocalDateTime time) { static String formatDateV3(LocalDateTime time) {
return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), "yyyy-MM-dd'T'HH:mm:ssXXX"); return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), UTC_WITH_XXX_OFFSET_PATTERN);
} }
static LocalDateTime parseDateV3(String time) { static LocalDateTime parseDateV3(String time) {
return LocalDateTimeUtil.parse(time, "yyyy-MM-dd'T'HH:mm:ssXXX"); return LocalDateTimeUtil.parse(time, UTC_WITH_XXX_OFFSET_PATTERN);
} }
} }

View File

@ -14,6 +14,8 @@ import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult;
import com.github.binarywang.wxpay.constant.WxPayConstants; import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.exception.WxPayException;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
public class WxBarPayClient extends AbstractWxPayClient { public class WxBarPayClient extends AbstractWxPayClient {
public WxBarPayClient(Long channelId, WxPayClientConfig config) { public WxBarPayClient(Long channelId, WxPayClientConfig config) {
@ -57,10 +59,11 @@ public class WxBarPayClient extends AbstractWxPayClient {
} }
// ========== 各种工具方法 ========== // ========== 各种工具方法 ==========
static String getAuthCode(PayOrderUnifiedReqDTO reqDTO) { static String getAuthCode(PayOrderUnifiedReqDTO reqDTO) {
String authCode = MapUtil.getStr(reqDTO.getChannelExtras(), "authCode"); String authCode = MapUtil.getStr(reqDTO.getChannelExtras(), "authCode");
if (StrUtil.isEmpty(authCode)) { if (StrUtil.isEmpty(authCode)) {
throw new IllegalArgumentException("支付请求的 authCode 不能为空!"); throw invalidParamException("支付请求的 authCode 不能为空!");
} }
return authCode; return authCode;
} }

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; package cn.iocoder.yudao.framework.pay.core.client.impl.weixin;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
@ -16,6 +18,8 @@ import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.exception.WxPayException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
/** /**
* 微信支付公众号 PayClient 实现类 * 微信支付公众号 PayClient 实现类
* *
@ -83,4 +87,14 @@ public class WxPubPayClient extends AbstractWxPayClient {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
// ========== 各种工具方法 ==========
static String getOpenid(PayOrderUnifiedReqDTO reqDTO) {
String openid = MapUtil.getStr(reqDTO.getChannelExtras(), "openid");
if (StrUtil.isEmpty(openid)) {
throw invalidParamException("支付请求的 openid 不能为空!");
}
return openid;
}
} }

View File

@ -11,19 +11,6 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
*/ */
public interface PayFrameworkErrorCodeConstants { public interface PayFrameworkErrorCodeConstants {
ErrorCode PAY_UNKNOWN = new ErrorCode(2002000000, "未知错误,需要解析"); ErrorCode ORDER_UNIFIED_ERROR = new ErrorCode(2002000000, "发起支付失败,原因:{}");
// ========== 配置相关相关 2002000100 ==========
// todo 芋艿如下的错误码怎么处理掉
ErrorCode PAY_CONFIG_APP_ID_ERROR = new ErrorCode(2002000100, "支付渠道 AppId 不正确");
ErrorCode PAY_CONFIG_SIGN_ERROR = new ErrorCode(2002000100, "签名错误"); // 例如说微信支付配置错了 mchId 或者 mchKey
// ========== 其它相关 2002000900 开头 ==========
// todo 芋艿如下的错误码怎么处理掉
ErrorCode PAY_OPENID_ERROR = new ErrorCode(2002000900, "无效的 openid"); // 例如说微信 openid 未授权过
ErrorCode PAY_PARAM_MISSING = new ErrorCode(2002000901, "请求参数缺失"); // 例如说支付少传了金额
ErrorCode PAY_EXCEPTION = new ErrorCode(2002000999, "调用异常");
} }