Commit efb221b1fec05117e882ed86e6b648b9083c9edb

Authored by YunaiV
1 parent e615be97

mall + pay:调整异常的处理

1. 如果是业务异常,则统一转换成 ServiceException
2. 如果是系统异常,则使用 PayException 包装成无需 check 的异常
Showing 13 changed files with 133 additions and 102 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/exception/util/ServiceExceptionUtil.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.common.exception.util; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.common.exception.util;
2 2
3 import cn.iocoder.yudao.framework.common.exception.ErrorCode; 3 import cn.iocoder.yudao.framework.common.exception.ErrorCode;
4 import cn.iocoder.yudao.framework.common.exception.ServiceException; 4 import cn.iocoder.yudao.framework.common.exception.ServiceException;
  5 +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
5 import com.google.common.annotations.VisibleForTesting; 6 import com.google.common.annotations.VisibleForTesting;
6 import lombok.extern.slf4j.Slf4j; 7 import lombok.extern.slf4j.Slf4j;
7 8
@@ -80,6 +81,10 @@ public class ServiceExceptionUtil { @@ -80,6 +81,10 @@ public class ServiceExceptionUtil {
80 return new ServiceException(code, message); 81 return new ServiceException(code, message);
81 } 82 }
82 83
  84 + public static ServiceException invalidParamException(String messagePattern, Object... params) {
  85 + return exception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(), messagePattern, params);
  86 + }
  87 +
83 // ========== 格式化方法 ========== 88 // ========== 格式化方法 ==========
84 89
85 /** 90 /**
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/exception/PayException.java
1 package cn.iocoder.yudao.framework.pay.core.client.exception; 1 package cn.iocoder.yudao.framework.pay.core.client.exception;
2 2
3 -import lombok.AllArgsConstructor;  
4 import lombok.Data; 3 import lombok.Data;
5 import lombok.EqualsAndHashCode; 4 import lombok.EqualsAndHashCode;
6 -import lombok.NoArgsConstructor;  
7 5
8 /** 6 /**
9 - * 业务逻辑异常 Exception 7 + * 支付系统异常 Exception
10 */ 8 */
11 @Data 9 @Data
12 @EqualsAndHashCode(callSuper = true) 10 @EqualsAndHashCode(callSuper = true)
13 -@NoArgsConstructor  
14 -@AllArgsConstructor  
15 public class PayException extends RuntimeException { 11 public class PayException extends RuntimeException {
16 12
17 - /**  
18 - * 第三方平台的错误码  
19 - */  
20 - private String code;  
21 - /**  
22 - * 第三方平台的错误提示  
23 - */  
24 - private String message; 13 + public PayException(Throwable cause) {
  14 + super(cause);
  15 + }
25 16
26 } 17 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
1 package cn.iocoder.yudao.framework.pay.core.client.impl; 1 package cn.iocoder.yudao.framework.pay.core.client.impl;
2 2
3 -import cn.hutool.core.date.LocalDateTimeUtil; 3 +import cn.iocoder.yudao.framework.common.exception.ServiceException;
4 import cn.iocoder.yudao.framework.pay.core.client.PayClient; 4 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
5 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; 5 import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig;
6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
7 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; 7 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
8 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; 8 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
9 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; 9 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO;
10 -import com.alipay.api.AlipayResponse; 10 +import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;
11 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
12 12
13 import javax.validation.Validation; 13 import javax.validation.Validation;
14 -import java.time.LocalDateTime;  
15 14
16 -import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;  
17 -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;  
18 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 15 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
19 -import static cn.iocoder.yudao.framework.pay.core.enums.PayFrameworkErrorCodeConstants.PAY_EXCEPTION;  
20 16
21 -// TODO 芋艿:优化下,替换异常;  
22 /** 17 /**
23 * 支付客户端的抽象类,提供模板方法,减少子类的冗余代码 18 * 支付客户端的抽象类,提供模板方法,减少子类的冗余代码
24 * 19 *
@@ -78,16 +73,19 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen @@ -78,16 +73,19 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
78 @Override 73 @Override
79 public final PayOrderUnifiedRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { 74 public final PayOrderUnifiedRespDTO unifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
80 Validation.buildDefaultValidatorFactory().getValidator().validate(reqDTO); 75 Validation.buildDefaultValidatorFactory().getValidator().validate(reqDTO);
81 - // 执行短信发送  
82 - PayOrderUnifiedRespDTO result; 76 + // 执行统一下单
  77 + PayOrderUnifiedRespDTO resp;
83 try { 78 try {
84 - result = doUnifiedOrder(reqDTO); 79 + resp = doUnifiedOrder(reqDTO);
  80 + } catch (ServiceException ex) {
  81 + // 业务异常,都是实现类已经翻译,所以直接抛出即可
  82 + throw ex;
85 } catch (Throwable ex) { 83 } catch (Throwable ex) {
86 - // 打印异常日志  
87 - log.error("[unifiedOrder][request({}) 发起支付失败]", toJsonString(reqDTO), ex); 84 + // 系统异常,则包装成 PayException 异常抛出
  85 + log.error("[unifiedRefund][request({}) 发起支付异常]", toJsonString(reqDTO), ex);
88 throw buildException(ex); 86 throw buildException(ex);
89 } 87 }
90 - return result; 88 + return resp;
91 } 89 }
92 90
93 protected abstract PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) 91 protected abstract PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO)
@@ -95,12 +93,17 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen @@ -95,12 +93,17 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
95 93
96 @Override 94 @Override
97 public PayRefundUnifiedRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO) { 95 public PayRefundUnifiedRespDTO unifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
  96 + Validation.buildDefaultValidatorFactory().getValidator().validate(reqDTO);
  97 + // 执行统一退款
98 PayRefundUnifiedRespDTO resp; 98 PayRefundUnifiedRespDTO resp;
99 try { 99 try {
100 resp = doUnifiedRefund(reqDTO); 100 resp = doUnifiedRefund(reqDTO);
101 - } catch (Throwable ex) {  
102 - // 记录异常日志  
103 - log.error("[unifiedRefund][request({}) 发起退款失败]", toJsonString(reqDTO), ex); 101 + } catch (ServiceException ex) {
  102 + // 业务异常,都是实现类已经翻译,所以直接抛出即可
  103 + throw ex;
  104 + } catch (Throwable ex) {
  105 + // 系统异常,则包装成 PayException 异常抛出
  106 + log.error("[unifiedRefund][request({}) 发起退款异常]", toJsonString(reqDTO), ex);
104 throw buildException(ex); 107 throw buildException(ex);
105 } 108 }
106 return resp; 109 return resp;
@@ -110,32 +113,11 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen @@ -110,32 +113,11 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
110 113
111 // ========== 各种工具方法 ========== 114 // ========== 各种工具方法 ==========
112 115
113 - private RuntimeException buildException(Throwable ex) {  
114 - if (ex instanceof RuntimeException) {  
115 - return (RuntimeException) ex;  
116 - }  
117 - throw new RuntimeException(ex);  
118 - }  
119 -  
120 - protected void validateSuccess(AlipayResponse response) {  
121 - if (response.isSuccess()) {  
122 - return; 116 + private PayException buildException(Throwable ex) {
  117 + if (ex instanceof PayException) {
  118 + return (PayException) ex;
123 } 119 }
124 - throw exception0(PAY_EXCEPTION.getCode(), response.getSubMsg());  
125 - }  
126 -  
127 - protected String formatAmount(Integer amount) {  
128 - return String.valueOf(amount / 100.0);  
129 - }  
130 -  
131 - protected String formatTime(LocalDateTime time) {  
132 - // "yyyy-MM-dd HH:mm:ss"  
133 - return LocalDateTimeUtil.format(time, NORM_DATETIME_FORMATTER);  
134 - }  
135 -  
136 - protected LocalDateTime parseTime(String str) {  
137 - // "yyyy-MM-dd HH:mm:ss"  
138 - return LocalDateTimeUtil.parse(str, NORM_DATETIME_FORMATTER); 120 + throw new PayException(ex);
139 } 121 }
140 122
141 } 123 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
1 package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; 1 package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
2 2
3 import cn.hutool.core.bean.BeanUtil; 3 import cn.hutool.core.bean.BeanUtil;
  4 +import cn.hutool.core.date.LocalDateTimeUtil;
4 import cn.hutool.http.HttpUtil; 5 import cn.hutool.http.HttpUtil;
  6 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
5 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; 7 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
6 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; 8 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
7 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO; 9 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 @@ -9,9 +11,7 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReq
9 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO; 11 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedRespDTO;
10 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; 12 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
11 import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum; 13 import cn.iocoder.yudao.framework.pay.core.enums.PayNotifyRefundStatusEnum;
12 -import com.alipay.api.AlipayApiException;  
13 -import com.alipay.api.AlipayConfig;  
14 -import com.alipay.api.DefaultAlipayClient; 14 +import com.alipay.api.*;
15 import com.alipay.api.domain.AlipayTradeRefundModel; 15 import com.alipay.api.domain.AlipayTradeRefundModel;
16 import com.alipay.api.internal.util.AlipaySignature; 16 import com.alipay.api.internal.util.AlipaySignature;
17 import com.alipay.api.request.AlipayTradeRefundRequest; 17 import com.alipay.api.request.AlipayTradeRefundRequest;
@@ -20,9 +20,13 @@ import lombok.SneakyThrows; @@ -20,9 +20,13 @@ import lombok.SneakyThrows;
20 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
21 21
22 import java.nio.charset.StandardCharsets; 22 import java.nio.charset.StandardCharsets;
  23 +import java.time.LocalDateTime;
23 import java.util.Map; 24 import java.util.Map;
24 25
  26 +import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;
  27 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
25 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 28 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
  29 +import static cn.iocoder.yudao.framework.pay.core.enums.PayFrameworkErrorCodeConstants.ORDER_UNIFIED_ERROR;
26 30
27 /** 31 /**
28 * 支付宝抽象类,实现支付宝统一的接口、以及部分实现(退款) 32 * 支付宝抽象类,实现支付宝统一的接口、以及部分实现(退款)
@@ -58,7 +62,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa @@ -58,7 +62,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
58 model.setOutTradeNo(reqDTO.getPayTradeNo()); 62 model.setOutTradeNo(reqDTO.getPayTradeNo());
59 63
60 model.setOutRequestNo(reqDTO.getMerchantRefundId()); 64 model.setOutRequestNo(reqDTO.getMerchantRefundId());
61 - model.setRefundAmount(formatAmount(reqDTO.getAmount()).toString()); 65 + model.setRefundAmount(formatAmount(reqDTO.getAmount()));
62 model.setRefundReason(reqDTO.getReason()); 66 model.setRefundReason(reqDTO.getReason());
63 67
64 AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest(); 68 AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest();
@@ -114,4 +118,35 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa @@ -114,4 +118,35 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
114 .build(); 118 .build();
115 } 119 }
116 120
  121 + // ========== 各种工具方法 ==========
  122 +
  123 + protected String formatAmount(Integer amount) {
  124 + return String.valueOf(amount / 100.0);
  125 + }
  126 +
  127 + protected String formatTime(LocalDateTime time) {
  128 + return LocalDateTimeUtil.format(time, NORM_DATETIME_FORMATTER);
  129 + }
  130 +
  131 + protected LocalDateTime parseTime(String str) {
  132 + return LocalDateTimeUtil.parse(str, NORM_DATETIME_FORMATTER);
  133 + }
  134 +
  135 + /**
  136 + * 校验支付宝统一下单的响应
  137 + *
  138 + * 如果校验不通过,则抛出 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 异常
  139 + *
  140 + * @param request 请求
  141 + * @param response 响应
  142 + */
  143 + protected void validateUnifiedOrderResponse(Object request, AlipayResponse response) {
  144 + if (response.isSuccess()) {
  145 + return;
  146 + }
  147 + log.error("[validateUnifiedOrderResponse][发起支付失败,request({}),response({})]",
  148 + JsonUtils.toJsonString(request), JsonUtils.toJsonString(response));
  149 + throw exception0(ORDER_UNIFIED_ERROR.getCode(), response.getSubMsg());
  150 + }
  151 +
117 } 152 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayAppPayClient.java
@@ -49,7 +49,7 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient { @@ -49,7 +49,7 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient {
49 // 2.1 执行请求 49 // 2.1 执行请求
50 AlipayTradeAppPayResponse response = client.execute(request); 50 AlipayTradeAppPayResponse response = client.execute(request);
51 // 2.2 处理结果 51 // 2.2 处理结果
52 - validateSuccess(response); 52 + validateUnifiedOrderResponse(request, response);
53 return new PayOrderUnifiedRespDTO() 53 return new PayOrderUnifiedRespDTO()
54 .setDisplayMode(displayMode).setDisplayContent(""); 54 .setDisplayMode(displayMode).setDisplayContent("");
55 } 55 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayBarPayClient.java
@@ -13,7 +13,6 @@ import com.alipay.api.response.AlipayTradePayResponse; @@ -13,7 +13,6 @@ import com.alipay.api.response.AlipayTradePayResponse;
13 import lombok.extern.slf4j.Slf4j; 13 import lombok.extern.slf4j.Slf4j;
14 14
15 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; 15 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
16 -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;  
17 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0; 16 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
18 17
19 /** 18 /**
@@ -59,8 +58,9 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient { @@ -59,8 +58,9 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient {
59 // 2.1 执行请求 58 // 2.1 执行请求
60 AlipayTradePayResponse response = client.execute(request); 59 AlipayTradePayResponse response = client.execute(request);
61 // 2.2 处理结果 60 // 2.2 处理结果
62 - validateSuccess(response); 61 + validateUnifiedOrderResponse(request, response);
63 return new PayOrderUnifiedRespDTO() 62 return new PayOrderUnifiedRespDTO()
64 .setDisplayMode(displayMode).setDisplayContent(""); 63 .setDisplayMode(displayMode).setDisplayContent("");
65 } 64 }
  65 +
66 } 66 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java
@@ -59,9 +59,8 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient { @@ -59,9 +59,8 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient {
59 } else { 59 } else {
60 response = client.pageExecute(request, Method.GET.name()); 60 response = client.pageExecute(request, Method.GET.name());
61 } 61 }
62 -  
63 // 2.2 处理结果 62 // 2.2 处理结果
64 - validateSuccess(response); 63 + validateUnifiedOrderResponse(request, response);
65 return new PayOrderUnifiedRespDTO().setDisplayMode(displayMode) 64 return new PayOrderUnifiedRespDTO().setDisplayMode(displayMode)
66 .setDisplayContent(response.getBody()); 65 .setDisplayContent(response.getBody());
67 } 66 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java
@@ -47,7 +47,7 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient { @@ -47,7 +47,7 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient {
47 // 2.1 执行请求 47 // 2.1 执行请求
48 AlipayTradePrecreateResponse response = client.execute(request); 48 AlipayTradePrecreateResponse response = client.execute(request);
49 // 2.2 处理结果 49 // 2.2 处理结果
50 - validateSuccess(response); 50 + validateUnifiedOrderResponse(request, response);
51 return new PayOrderUnifiedRespDTO() 51 return new PayOrderUnifiedRespDTO()
52 .setDisplayMode(displayMode).setDisplayContent(response.getQrCode()); 52 .setDisplayMode(displayMode).setDisplayContent(response.getQrCode());
53 } 53 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java
@@ -50,7 +50,7 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient { @@ -50,7 +50,7 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient {
50 AlipayTradeWapPayResponse response = client.pageExecute(request, Method.GET.name()); 50 AlipayTradeWapPayResponse response = client.pageExecute(request, Method.GET.name());
51 51
52 // 2.2 处理结果 52 // 2.2 处理结果
53 - validateSuccess(response); 53 + validateUnifiedOrderResponse(request, response);
54 return new PayOrderUnifiedRespDTO() 54 return new PayOrderUnifiedRespDTO()
55 .setDisplayMode(displayMode).setDisplayContent(response.getBody()); 55 .setDisplayMode(displayMode).setDisplayContent(response.getBody());
56 } 56 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
@@ -4,16 +4,14 @@ import cn.hutool.core.bean.BeanUtil; @@ -4,16 +4,14 @@ import cn.hutool.core.bean.BeanUtil;
4 import cn.hutool.core.date.LocalDateTimeUtil; 4 import cn.hutool.core.date.LocalDateTimeUtil;
5 import cn.hutool.core.date.TemporalAccessorUtil; 5 import cn.hutool.core.date.TemporalAccessorUtil;
6 import cn.hutool.core.lang.Assert; 6 import cn.hutool.core.lang.Assert;
7 -import cn.hutool.core.map.MapUtil;  
8 import cn.hutool.core.util.StrUtil; 7 import cn.hutool.core.util.StrUtil;
9 import cn.iocoder.yudao.framework.common.util.io.FileUtils; 8 import cn.iocoder.yudao.framework.common.util.io.FileUtils;
10 -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;  
11 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO; 9 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
12 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; 10 import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
13 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 11 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
14 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; 12 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
15 -import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;  
16 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; 13 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
  14 +import cn.iocoder.yudao.framework.pay.core.enums.PayFrameworkErrorCodeConstants;
17 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; 15 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
18 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result; 16 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result;
19 import com.github.binarywang.wxpay.config.WxPayConfig; 17 import com.github.binarywang.wxpay.config.WxPayConfig;
@@ -26,6 +24,9 @@ import java.time.LocalDateTime; @@ -26,6 +24,9 @@ import java.time.LocalDateTime;
26 import java.time.ZoneId; 24 import java.time.ZoneId;
27 import java.util.Objects; 25 import java.util.Objects;
28 26
  27 +import static cn.hutool.core.date.DatePattern.PURE_DATETIME_PATTERN;
  28 +import static cn.hutool.core.date.DatePattern.UTC_WITH_XXX_OFFSET_PATTERN;
  29 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.*;
29 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 30 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
30 31
31 /** 32 /**
@@ -67,8 +68,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC @@ -67,8 +68,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
67 } 68 }
68 69
69 @Override 70 @Override
70 - protected PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO)  
71 - throws Throwable { 71 + protected PayOrderUnifiedRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws Exception {
72 try { 72 try {
73 switch (config.getApiVersion()) { 73 switch (config.getApiVersion()) {
74 case WxPayClientConfig.API_VERSION_V2: 74 case WxPayClientConfig.API_VERSION_V2:
@@ -79,8 +79,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC @@ -79,8 +79,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
79 throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); 79 throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
80 } 80 }
81 } catch (WxPayException e) { 81 } catch (WxPayException e) {
82 - log.error("[doUnifiedOrder][request({}) 发起支付失败]", toJsonString(reqDTO), e);  
83 - throw buildPayException(e); 82 + throw buildUnifiedOrderException(reqDTO, e);
84 } 83 }
85 } 84 }
86 85
@@ -118,7 +117,9 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC @@ -118,7 +117,9 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
118 } 117 }
119 } catch (WxPayException e) { 118 } catch (WxPayException e) {
120 log.error("[parseNotify][rawNotify({}) 解析失败]", toJsonString(rawNotify), e); 119 log.error("[parseNotify][rawNotify({}) 解析失败]", toJsonString(rawNotify), e);
121 - throw buildPayException(e); 120 +// throw buildPayException(e);
  121 + throw new RuntimeException(e);
  122 + // TODO 芋艿:缺一个异常翻译
122 } 123 }
123 } 124 }
124 125
@@ -151,33 +152,47 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC @@ -151,33 +152,47 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
151 152
152 // ========== 各种工具方法 ========== 153 // ========== 各种工具方法 ==========
153 154
154 - static String getOpenid(PayOrderUnifiedReqDTO reqDTO) {  
155 - String openid = MapUtil.getStr(reqDTO.getChannelExtras(), "openid");  
156 - if (StrUtil.isEmpty(openid)) {  
157 - throw new IllegalArgumentException("支付请求的 openid 不能为空!"); 155 + /**
  156 + * 构建统一下单的异常
  157 + *
  158 + * 目的:将参数不正确等异常,转换成 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 业务异常
  159 + *
  160 + * @param reqDTO 请求
  161 + * @param e 微信的支付异常
  162 + * @return 转换后的异常
  163 + *
  164 + */
  165 + static Exception buildUnifiedOrderException(PayOrderUnifiedReqDTO reqDTO, WxPayException e) {
  166 + // 情况一:业务结果为 FAIL
  167 + if (Objects.equals(e.getResultCode(), "FAIL")) {
  168 + log.error("[buildUnifiedOrderException][request({}) 发起支付失败]", toJsonString(reqDTO), e);
  169 + if (Objects.equals(e.getErrCode(), "PARAM_ERROR")) {
  170 + throw invalidParamException(e.getErrCodeDes());
  171 + }
  172 + throw exception(PayFrameworkErrorCodeConstants.ORDER_UNIFIED_ERROR, e.getReturnMsg());
158 } 173 }
159 - return openid;  
160 - }  
161 -  
162 - static PayException buildPayException(WxPayException e) {  
163 - return new PayException(ObjectUtils.defaultIfNull(e.getErrCode(), e.getReturnCode()),  
164 - ObjectUtils.defaultIfNull(e.getErrCodeDes(), e.getCustomErrorMsg())); 174 + // 情况二:状态码结果为 FAIL
  175 + if (Objects.equals(e.getReturnCode(), "FAIL")) {
  176 + throw exception(PayFrameworkErrorCodeConstants.ORDER_UNIFIED_ERROR, e.getReturnMsg());
  177 + }
  178 + // 情况三:系统异常,这里暂时不打,交给上层的 AbstractPayClient 统一打
  179 + return e;
165 } 180 }
166 181
167 static String formatDateV2(LocalDateTime time) { 182 static String formatDateV2(LocalDateTime time) {
168 - return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), "yyyyMMddHHmmss"); 183 + return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), PURE_DATETIME_PATTERN);
169 } 184 }
170 185
171 static LocalDateTime parseDateV2(String time) { 186 static LocalDateTime parseDateV2(String time) {
172 - return LocalDateTimeUtil.parse(time, "yyyyMMddHHmmss"); 187 + return LocalDateTimeUtil.parse(time, PURE_DATETIME_PATTERN);
173 } 188 }
174 189
175 static String formatDateV3(LocalDateTime time) { 190 static String formatDateV3(LocalDateTime time) {
176 - return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), "yyyy-MM-dd'T'HH:mm:ssXXX"); 191 + return TemporalAccessorUtil.format(time.atZone(ZoneId.systemDefault()), UTC_WITH_XXX_OFFSET_PATTERN);
177 } 192 }
178 193
179 static LocalDateTime parseDateV3(String time) { 194 static LocalDateTime parseDateV3(String time) {
180 - return LocalDateTimeUtil.parse(time, "yyyy-MM-dd'T'HH:mm:ssXXX"); 195 + return LocalDateTimeUtil.parse(time, UTC_WITH_XXX_OFFSET_PATTERN);
181 } 196 }
182 197
183 } 198 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxBarPayClient.java
@@ -14,6 +14,8 @@ import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult; @@ -14,6 +14,8 @@ import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult;
14 import com.github.binarywang.wxpay.constant.WxPayConstants; 14 import com.github.binarywang.wxpay.constant.WxPayConstants;
15 import com.github.binarywang.wxpay.exception.WxPayException; 15 import com.github.binarywang.wxpay.exception.WxPayException;
16 16
  17 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
  18 +
17 public class WxBarPayClient extends AbstractWxPayClient { 19 public class WxBarPayClient extends AbstractWxPayClient {
18 20
19 public WxBarPayClient(Long channelId, WxPayClientConfig config) { 21 public WxBarPayClient(Long channelId, WxPayClientConfig config) {
@@ -57,10 +59,11 @@ public class WxBarPayClient extends AbstractWxPayClient { @@ -57,10 +59,11 @@ public class WxBarPayClient extends AbstractWxPayClient {
57 } 59 }
58 60
59 // ========== 各种工具方法 ========== 61 // ========== 各种工具方法 ==========
  62 +
60 static String getAuthCode(PayOrderUnifiedReqDTO reqDTO) { 63 static String getAuthCode(PayOrderUnifiedReqDTO reqDTO) {
61 String authCode = MapUtil.getStr(reqDTO.getChannelExtras(), "authCode"); 64 String authCode = MapUtil.getStr(reqDTO.getChannelExtras(), "authCode");
62 if (StrUtil.isEmpty(authCode)) { 65 if (StrUtil.isEmpty(authCode)) {
63 - throw new IllegalArgumentException("支付请求的 authCode 不能为空!"); 66 + throw invalidParamException("支付请求的 authCode 不能为空!");
64 } 67 }
65 return authCode; 68 return authCode;
66 } 69 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/WxPubPayClient.java
1 package cn.iocoder.yudao.framework.pay.core.client.impl.weixin; 1 package cn.iocoder.yudao.framework.pay.core.client.impl.weixin;
2 2
  3 +import cn.hutool.core.map.MapUtil;
  4 +import cn.hutool.core.util.StrUtil;
3 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 5 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
4 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; 6 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
5 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; 7 import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
@@ -16,6 +18,8 @@ import com.github.binarywang.wxpay.constant.WxPayConstants; @@ -16,6 +18,8 @@ import com.github.binarywang.wxpay.constant.WxPayConstants;
16 import com.github.binarywang.wxpay.exception.WxPayException; 18 import com.github.binarywang.wxpay.exception.WxPayException;
17 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
18 20
  21 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
  22 +
19 /** 23 /**
20 * 微信支付(公众号)的 PayClient 实现类 24 * 微信支付(公众号)的 PayClient 实现类
21 * 25 *
@@ -83,4 +87,14 @@ public class WxPubPayClient extends AbstractWxPayClient { @@ -83,4 +87,14 @@ public class WxPubPayClient extends AbstractWxPayClient {
83 throw new UnsupportedOperationException(); 87 throw new UnsupportedOperationException();
84 } 88 }
85 89
  90 + // ========== 各种工具方法 ==========
  91 +
  92 + static String getOpenid(PayOrderUnifiedReqDTO reqDTO) {
  93 + String openid = MapUtil.getStr(reqDTO.getChannelExtras(), "openid");
  94 + if (StrUtil.isEmpty(openid)) {
  95 + throw invalidParamException("支付请求的 openid 不能为空!");
  96 + }
  97 + return openid;
  98 + }
  99 +
86 } 100 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayFrameworkErrorCodeConstants.java
@@ -11,19 +11,6 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; @@ -11,19 +11,6 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
11 */ 11 */
12 public interface PayFrameworkErrorCodeConstants { 12 public interface PayFrameworkErrorCodeConstants {
13 13
14 - ErrorCode PAY_UNKNOWN = new ErrorCode(2002000000, "未知错误,需要解析");  
15 -  
16 - // ========== 配置相关相关 2002000100 ==========  
17 - // todo 芋艿:如下的错误码,怎么处理掉  
18 - ErrorCode PAY_CONFIG_APP_ID_ERROR = new ErrorCode(2002000100, "支付渠道 AppId 不正确");  
19 - ErrorCode PAY_CONFIG_SIGN_ERROR = new ErrorCode(2002000100, "签名错误"); // 例如说,微信支付,配置错了 mchId 或者 mchKey  
20 -  
21 -  
22 - // ========== 其它相关 2002000900 开头 ==========  
23 - // todo 芋艿:如下的错误码,怎么处理掉  
24 - ErrorCode PAY_OPENID_ERROR = new ErrorCode(2002000900, "无效的 openid"); // 例如说,微信 openid 未授权过  
25 - ErrorCode PAY_PARAM_MISSING = new ErrorCode(2002000901, "请求参数缺失"); // 例如说,支付少传了金额  
26 -  
27 - ErrorCode PAY_EXCEPTION = new ErrorCode(2002000999, "调用异常"); 14 + ErrorCode ORDER_UNIFIED_ERROR = new ErrorCode(2002000000, "发起支付失败,原因:{}");
28 15
29 } 16 }