diff --git a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java b/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java index 8e80512f89..7439b33aca 100644 --- a/yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java +++ b/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 params, String body, Map headers) throws Throwable { // 1. 校验回调数据 - Map bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8); - boolean verify; - if (Objects.equals(config.getMode(), MODE_PUBLIC_KEY)) { - verify = AlipaySignature.rsaCheckV1(params, config.getAlipayPublicKey(), - StandardCharsets.UTF_8.name(), config.getSignType()); - } else if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { - // 由于 rsaCertCheckV1 的第二个参数是 path,所以不能这么调用!!!通过阅读源码,发现可以采用如下方式! - X509Certificate cert = AntCertificationUtil.getCertFromContent(config.getAlipayPublicCertContent()); - String publicKey = Base64.encodeBase64String(cert.getEncoded()); - verify = AlipaySignature.rsaCheckV1(bodyObj, publicKey, - StandardCharsets.UTF_8.name(), config.getSignType()); - } else { - throw new IllegalArgumentException("未知的公钥类型:" + config.getMode()); - } - Assert.isTrue(verify, "验签结果不通过"); + verifyNotifyData(params); // 2. 解析订单的状态 // 额外说明:支付宝不仅仅支付成功会回调,再各种触发支付单数据变化时,都会进行回调,所以这里 status 的解析会写的比较复杂 + Map bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8); Integer status = parseStatus(bodyObj.get("trade_status")); // 特殊逻辑: 支付宝没有退款成功的状态,所以,如果有退款金额,我们认为是退款成功 if (MapUtil.getDouble(bodyObj, "refund_fee", 0D) > 0) { @@ -324,10 +311,55 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient params, String body, Map headers) { - throw new UnsupportedOperationException("未实现"); + protected PayTransferRespDTO doParseTransferNotify(Map params, String body, Map headers) + throws Throwable { + // 1. 校验回调数据 + verifyNotifyData(params); + + // 2. 解析转账状态 + Map bodyObj = HttpUtil.decodeParamMap(body, StandardCharsets.UTF_8); + String status = bodyObj.get("status"); + String outBizNo = bodyObj.get("out_biz_no"); + String orderId = bodyObj.get("order_id"); + String payDate = bodyObj.get("pay_date"); + + // 3. 根据状态返回对应的结果 + if (Objects.equals(status, "SUCCESS")) { + return PayTransferRespDTO.successOf(orderId, parseTime(payDate), outBizNo, bodyObj); + } + if (Objects.equals(status, "DEALING")) { + return PayTransferRespDTO.processingOf(orderId, outBizNo, bodyObj); + } + if (ObjectUtils.equalsAny(status, "REFUND", "FAIL")) { + return PayTransferRespDTO.closedOf(bodyObj.get("sub_code"), bodyObj.get("sub_msg"), + outBizNo, bodyObj); + } + return PayTransferRespDTO.waitingOf(orderId, outBizNo, bodyObj); + } + + /** + * 校验回调数据 + * + * @param params 回调参数 + * @throws Throwable 验签失败时抛出异常 + */ + protected void verifyNotifyData(Map params) throws Throwable { + boolean verify; + if (Objects.equals(config.getMode(), MODE_PUBLIC_KEY)) { + verify = AlipaySignature.rsaCheckV1(params, config.getAlipayPublicKey(), + StandardCharsets.UTF_8.name(), config.getSignType()); + } else if (Objects.equals(config.getMode(), MODE_CERTIFICATE)) { + // 由于 rsaCertCheckV1 的第二个参数是 path,所以不能这么调用!!!通过阅读源码,发现可以采用如下方式! + X509Certificate cert = AntCertificationUtil.getCertFromContent(config.getAlipayPublicCertContent()); + String publicKey = Base64.encodeBase64String(cert.getEncoded()); + verify = AlipaySignature.rsaCheckV1(params, publicKey, + StandardCharsets.UTF_8.name(), config.getSignType()); + } else { + throw new IllegalArgumentException("未知的公钥类型:" + config.getMode()); + } + Assert.isTrue(verify, "验签结果不通过"); } // ========== 各种工具方法 ==========