Commit f81dc105a2a4a438d43f5a6487b8cf25f68ddd93

Authored by YunaiV
1 parent 7653be9d

feat:【PAY 支付】AbstractAlipayPayClient,支付宝增加回调解析

yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
... ... @@ -81,24 +81,11 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
81 81 @Override
82 82 public PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body, Map<String, String> headers) throws Throwable {
83 83 // 1. 校验回调数据
84   - Map<String, String> bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8);
85   - boolean verify;
86   - if (Objects.equals(config.getMode(), MODE_PUBLIC_KEY)) {
87   - verify = AlipaySignature.rsaCheckV1(params, config.getAlipayPublicKey(),
88   - StandardCharsets.UTF_8.name(), config.getSignType());
89   - } else if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) {
90   - // 由于 rsaCertCheckV1 的第二个参数是 path,所以不能这么调用!!!通过阅读源码,发现可以采用如下方式!
91   - X509Certificate cert = AntCertificationUtil.getCertFromContent(config.getAlipayPublicCertContent());
92   - String publicKey = Base64.encodeBase64String(cert.getEncoded());
93   - verify = AlipaySignature.rsaCheckV1(bodyObj, publicKey,
94   - StandardCharsets.UTF_8.name(), config.getSignType());
95   - } else {
96   - throw new IllegalArgumentException("未知的公钥类型:" + config.getMode());
97   - }
98   - Assert.isTrue(verify, "验签结果不通过");
  84 + verifyNotifyData(params);
99 85  
100 86 // 2. 解析订单的状态
101 87 // 额外说明:支付宝不仅仅支付成功会回调,再各种触发支付单数据变化时,都会进行回调,所以这里 status 的解析会写的比较复杂
  88 + Map<String, String> bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8);
102 89 Integer status = parseStatus(bodyObj.get("trade_status"));
103 90 // 特殊逻辑: 支付宝没有退款成功的状态,所以,如果有退款金额,我们认为是退款成功
104 91 if (MapUtil.getDouble(bodyObj, "refund_fee", 0D) > 0) {
... ... @@ -324,10 +311,55 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient&lt;AlipayPa
324 311 response.getOutBizNo(), response);
325 312 }
326 313  
327   - // TODO @chihuo:这里是不是也要实现,支付宝的。
  314 + // TODO @芋艿:由于支付宝一直没触发回调,这个方法暂时没办法测试
328 315 @Override
329   - protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers) {
330   - throw new UnsupportedOperationException("未实现");
  316 + protected PayTransferRespDTO doParseTransferNotify(Map<String, String> params, String body, Map<String, String> headers)
  317 + throws Throwable {
  318 + // 1. 校验回调数据
  319 + verifyNotifyData(params);
  320 +
  321 + // 2. 解析转账状态
  322 + Map<String, String> bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8);
  323 + String status = bodyObj.get("status");
  324 + String outBizNo = bodyObj.get("out_biz_no");
  325 + String orderId = bodyObj.get("order_id");
  326 + String payDate = bodyObj.get("pay_date");
  327 +
  328 + // 3. 根据状态返回对应的结果
  329 + if (Objects.equals(status, "SUCCESS")) {
  330 + return PayTransferRespDTO.successOf(orderId, parseTime(payDate), outBizNo, bodyObj);
  331 + }
  332 + if (Objects.equals(status, "DEALING")) {
  333 + return PayTransferRespDTO.processingOf(orderId, outBizNo, bodyObj);
  334 + }
  335 + if (ObjectUtils.equalsAny(status, "REFUND", "FAIL")) {
  336 + return PayTransferRespDTO.closedOf(bodyObj.get("sub_code"), bodyObj.get("sub_msg"),
  337 + outBizNo, bodyObj);
  338 + }
  339 + return PayTransferRespDTO.waitingOf(orderId, outBizNo, bodyObj);
  340 + }
  341 +
  342 + /**
  343 + * 校验回调数据
  344 + *
  345 + * @param params 回调参数
  346 + * @throws Throwable 验签失败时抛出异常
  347 + */
  348 + protected void verifyNotifyData(Map<String, String> params) throws Throwable {
  349 + boolean verify;
  350 + if (Objects.equals(config.getMode(), MODE_PUBLIC_KEY)) {
  351 + verify = AlipaySignature.rsaCheckV1(params, config.getAlipayPublicKey(),
  352 + StandardCharsets.UTF_8.name(), config.getSignType());
  353 + } else if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) {
  354 + // 由于 rsaCertCheckV1 的第二个参数是 path,所以不能这么调用!!!通过阅读源码,发现可以采用如下方式!
  355 + X509Certificate cert = AntCertificationUtil.getCertFromContent(config.getAlipayPublicCertContent());
  356 + String publicKey = Base64.encodeBase64String(cert.getEncoded());
  357 + verify = AlipaySignature.rsaCheckV1(params, publicKey,
  358 + StandardCharsets.UTF_8.name(), config.getSignType());
  359 + } else {
  360 + throw new IllegalArgumentException("未知的公钥类型:" + config.getMode());
  361 + }
  362 + Assert.isTrue(verify, "验签结果不通过");
331 363 }
332 364  
333 365 // ========== 各种工具方法 ==========
... ...