From 72ac03f842a5f3fcb66e9139c22f24559bb53be3 Mon Sep 17 00:00:00 2001 From: bootx Date: Sun, 16 Jun 2024 17:20:39 +0800 Subject: [PATCH] =?UTF-8?q?ref=20=E6=94=AF=E4=BB=98=E5=AE=9D=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E6=9B=BF=E6=8D=A2=E4=B8=BA=E5=8E=9F=E7=94=9FSDK?= =?UTF-8?q?=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../single/sdk/param/channel/AliPayParam.java | 15 ++- .../single/param/channel/AliPayParam.java | 16 +++ .../single/service/code/AliPayCode.java | 3 + .../alipay/service/AliPayConfigService.java | 37 ++++++- .../channel/alipay/service/AliPayService.java | 103 +++++++++++++++--- .../service/core/extra/AliPayAuthService.java | 24 +--- 6 files changed, 154 insertions(+), 44 deletions(-) diff --git a/daxpay-single-sdk/src/main/java/cn/daxpay/single/sdk/param/channel/AliPayParam.java b/daxpay-single-sdk/src/main/java/cn/daxpay/single/sdk/param/channel/AliPayParam.java index 4e612c8f..11881a18 100644 --- a/daxpay-single-sdk/src/main/java/cn/daxpay/single/sdk/param/channel/AliPayParam.java +++ b/daxpay-single-sdk/src/main/java/cn/daxpay/single/sdk/param/channel/AliPayParam.java @@ -13,7 +13,20 @@ import lombok.Setter; @Setter public class AliPayParam implements ChannelParam { - /** 授权码(主动扫描用户的付款码) */ + /** + * 授权码(主动扫描用户的付款码) + */ private String authCode; + /** + * 【描述】小程序支付中,商户实际经营主体的小程序应用的appid,也即最终唤起收银台支付所在的小程序的应用id + * 【注意事项】商户需要先在产品管理中心绑定该小程序appid,否则下单会失败 + */ + private String opAppId; + + /** + * 买家支付宝用户唯一标识 + */ + private String openId; + } diff --git a/daxpay-single/daxpay-single-core/src/main/java/cn/daxpay/single/param/channel/AliPayParam.java b/daxpay-single/daxpay-single-core/src/main/java/cn/daxpay/single/param/channel/AliPayParam.java index 16c617a3..981c6e39 100644 --- a/daxpay-single/daxpay-single-core/src/main/java/cn/daxpay/single/param/channel/AliPayParam.java +++ b/daxpay-single/daxpay-single-core/src/main/java/cn/daxpay/single/param/channel/AliPayParam.java @@ -12,7 +12,23 @@ import lombok.Data; @Schema(title = "支付宝支付参数") public class AliPayParam implements ChannelParam { + /** + * 授权码(主动扫描用户的付款码) + */ @Schema(description = "授权码(主动扫描用户的付款码)") private String authCode; + /** + * 【描述】小程序支付中,商户实际经营主体的小程序应用的appid,也即最终唤起收银台支付所在的小程序的应用id + * 【注意事项】商户需要先在产品管理中心绑定该小程序appid,否则下单会失败 + */ + @Schema(description = "商户实际经营主体的小程序应用的appid") + private String opAppId; + + /** + * 买家支付宝用户唯一标识 + */ + @Schema(description = "买家支付宝用户唯一标识") + private String openId; + } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/code/AliPayCode.java b/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/code/AliPayCode.java index a28f0ef1..d095fbb9 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/code/AliPayCode.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/code/AliPayCode.java @@ -28,6 +28,9 @@ public interface AliPayCode { /** 询余额账户类型 */ String QUERY_ACCOUNT_TYPE = "ACCTRANS_ACCOUNT"; + /** jsapi */ + String JSAPI_PAY ="JSAPI_PAY"; + /** 付款码支付 */ String BAR_CODE = "bar_code"; diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/core/channel/alipay/service/AliPayConfigService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/core/channel/alipay/service/AliPayConfigService.java index 030f1c22..2bc533ae 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/core/channel/alipay/service/AliPayConfigService.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/core/channel/alipay/service/AliPayConfigService.java @@ -8,12 +8,14 @@ import cn.daxpay.single.service.code.AliPayCode; import cn.daxpay.single.service.code.AliPayWay; import cn.daxpay.single.service.core.channel.alipay.dao.AliPayConfigManager; import cn.daxpay.single.service.core.channel.alipay.entity.AliPayConfig; -import cn.daxpay.single.service.core.system.config.service.PayChannelConfigService; import cn.daxpay.single.service.core.system.config.service.PlatformConfigService; import cn.daxpay.single.service.param.channel.alipay.AliPayConfigParam; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.copier.CopyOptions; import cn.hutool.core.util.CharsetUtil; +import com.alipay.api.AlipayClient; +import com.alipay.api.AlipayConfig; +import com.alipay.api.DefaultAlipayClient; import com.ijpay.alipay.AliPayApiConfig; import com.ijpay.alipay.AliPayApiConfigKit; import lombok.RequiredArgsConstructor; @@ -39,7 +41,6 @@ public class AliPayConfigService { /** 默认支付宝配置的主键ID */ private final static Long ID = 0L; private final AliPayConfigManager alipayConfigManager; - private final PayChannelConfigService payChannelConfigService; private final PlatformConfigService platformConfigService; /** @@ -94,6 +95,38 @@ public class AliPayConfigService { return platformConfigService.getConfig().getWebsiteUrl() + "/return/pay/alipay"; } + /** + * 获取支付宝SDK的配置 + */ + public AlipayClient getAlipayClient(){ + AliPayConfig aliPayConfig = this.getConfig(); + return this.getAlipayClient(aliPayConfig); + } + + /** + * 获取支付宝SDK的配置 + */ + @SneakyThrows + public AlipayClient getAlipayClient(AliPayConfig aliPayConfig){ + AlipayConfig config = new AlipayConfig(); + config.setServerUrl(aliPayConfig.getServerUrl()); + config.setAppId(aliPayConfig.getAppId()); + config.setFormat("json"); + config.setCharset("UTF-8"); + config.setSignType(aliPayConfig.getSignType()); + // 证书 + if (Objects.equals(aliPayConfig.getAuthType(), AliPayCode.AUTH_TYPE_CART)){ + config.setAppCertContent(aliPayConfig.getAppCert()); + config.setRootCertContent(aliPayConfig.getAlipayRootCert()); + config.setAlipayPublicCertContent(aliPayConfig.getAlipayCert()); + } else { + // 公钥 + config.setPrivateKey(aliPayConfig.getPrivateKey()); + config.setAlipayPublicKey(aliPayConfig.getAlipayPublicKey()); + } + return new DefaultAlipayClient(config); + } + /** * 初始化IJPay服务 */ diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/core/channel/alipay/service/AliPayService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/core/channel/alipay/service/AliPayService.java index 350168b8..a1c3e2ca 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/core/channel/alipay/service/AliPayService.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/core/channel/alipay/service/AliPayService.java @@ -16,13 +16,14 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.Method; import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayClient; import com.alipay.api.AlipayResponse; import com.alipay.api.domain.*; -import com.alipay.api.request.AlipayTradePagePayRequest; -import com.alipay.api.request.AlipayTradeWapPayRequest; +import com.alipay.api.request.*; import com.alipay.api.response.*; import com.ijpay.alipay.AliPayApi; import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -44,6 +45,8 @@ import static cn.daxpay.single.service.code.AliPayCode.QUICK_MSECURITY_PAY; @RequiredArgsConstructor public class AliPayService { + private final AliPayConfigService aliPayConfigService; + /** * 支付前检查支付方式是否可用 */ @@ -54,7 +57,7 @@ public class AliPayService { } // 发起的支付类型是否在支持的范围内 PayMethodEnum payMethodEnum = Optional.ofNullable(AliPayWay.findByCode(payParam.getMethod())) - .orElseThrow(() -> new PayFailureException("非法的支付宝支付类型")); + .orElseThrow(() -> new PayFailureException("非法的支付宝支付类型")); if (!alipayConfig.getPayWays().contains(payMethodEnum.getCode())) { throw new PayFailureException("该支付宝支付方式不可用"); } @@ -88,6 +91,10 @@ public class AliPayService { else if (Objects.equals(payOrder.getMethod(), PayMethodEnum.WEB.getCode())) { payBody = this.webPay(amount, payOrder, alipayConfig); } + // jsapi支付 + else if (Objects.equals(payOrder.getMethod(), PayMethodEnum.JSAPI.getCode())) { + payBody = this.jsapiPay(amount, payOrder, aliPayParam, alipayConfig); + } // 二维码支付 else if (Objects.equals(payOrder.getMethod(), PayMethodEnum.QRCODE.getCode())) { payBody = this.qrCodePay(amount, payOrder, alipayConfig); @@ -103,7 +110,11 @@ public class AliPayService { /** * wap支付 */ + @SneakyThrows public String wapPay(String amount, PayOrder payOrder, AliPayConfig alipayConfig) { + // 获取支付宝客户端 + AlipayClient alipayClient = aliPayConfigService.getAlipayClient(alipayConfig); + AlipayTradeWapPayModel model = new AlipayTradeWapPayModel(); model.setSubject(payOrder.getTitle()); model.setOutTradeNo(payOrder.getOrderNo()); @@ -114,7 +125,7 @@ public class AliPayService { // 是否分账 if (payOrder.getAllocation()){ ExtendParams extendParams = new ExtendParams(); - extendParams.setRoyaltyFreeze("true"); + extendParams.setRoyaltyFreeze(Boolean.TRUE.toString()); model.setExtendParams(extendParams); } @@ -127,7 +138,7 @@ public class AliPayService { try { // 通过GET方式的请求, 返回URL的响应, 默认是POST方式的请求, 返回的是表单响应 - AlipayTradeWapPayResponse response = AliPayApi.pageExecute(request, Method.GET.name()); + AlipayTradeWapPayResponse response = alipayClient.pageExecute(request, Method.GET.name()); return response.getBody(); } catch (AlipayApiException e) { @@ -139,9 +150,12 @@ public class AliPayService { /** * app支付 */ + @SneakyThrows public String appPay(String amount, PayOrder payOrder, AliPayConfig alipayConfig) { - AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); + // 获取支付宝客户端 + AlipayClient alipayClient = aliPayConfigService.getAlipayClient(alipayConfig); + AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); model.setSubject(payOrder.getTitle()); model.setProductCode(QUICK_MSECURITY_PAY); model.setOutTradeNo(payOrder.getOrderNo()); @@ -151,13 +165,15 @@ public class AliPayService { // 是否分账 if (payOrder.getAllocation()){ ExtendParams extendParams = new ExtendParams(); - extendParams.setRoyaltyFreeze("true"); + extendParams.setRoyaltyFreeze(Boolean.TRUE.toString()); model.setExtendParams(extendParams); } - + AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest(); + request.setBizModel(model); + request.setNotifyUrl(alipayConfig.getNotifyUrl()); try { // 异步回调必须到当前系统中 - AlipayTradeAppPayResponse response = AliPayApi.appPayToResponse(model, alipayConfig.getNotifyUrl()); + AlipayTradeAppPayResponse response = alipayClient.execute(request); return response.getBody(); } catch (AlipayApiException e) { @@ -169,9 +185,12 @@ public class AliPayService { /** * PC支付 */ + @SneakyThrows public String webPay(String amount, PayOrder payOrder, AliPayConfig alipayConfig) { - AlipayTradePagePayModel model = new AlipayTradePagePayModel(); + // 获取支付宝客户端 + AlipayClient alipayClient = aliPayConfigService.getAlipayClient(alipayConfig); + AlipayTradePagePayModel model = new AlipayTradePagePayModel(); model.setSubject(payOrder.getTitle()); model.setOutTradeNo(payOrder.getOrderNo()); // 过期时间 @@ -183,7 +202,7 @@ public class AliPayService { // 是否分账 if (payOrder.getAllocation()){ ExtendParams extendParams = new ExtendParams(); - extendParams.setRoyaltyFreeze("true"); + extendParams.setRoyaltyFreeze(Boolean.TRUE.toString()); model.setExtendParams(extendParams); } @@ -195,7 +214,7 @@ public class AliPayService { request.setReturnUrl(alipayConfig.getReturnUrl()); try { // 通过GET方式的请求, 返回URL的响应, 默认是POST方式的请求, 返回的是表单响应 - AlipayTradePagePayResponse response = AliPayApi.pageExecute(request, Method.GET.name()); + AlipayTradePagePayResponse response = alipayClient.pageExecute(request, Method.GET.name()); return response.getBody(); } catch (AlipayApiException e) { @@ -204,10 +223,50 @@ public class AliPayService { } } + /** + * jsapi支付 + */ + @SneakyThrows + public String jsapiPay(String amount, PayOrder payOrder, AliPayParam aliPayParam, AliPayConfig alipayConfig) { + // 获取支付宝客户端 + AlipayClient alipayClient = aliPayConfigService.getAlipayClient(alipayConfig); + + // 构造请求参数以调用接口 + AlipayTradeCreateRequest request = new AlipayTradeCreateRequest(); + AlipayTradeCreateModel model = new AlipayTradeCreateModel(); + model.setOutTradeNo(payOrder.getOrderNo()); + model.setProductCode(AliPayCode.JSAPI_PAY); + model.setOpAppId(aliPayParam.getOpAppId()); + model.setTotalAmount(amount); + model.setSubject(payOrder.getTitle()); + model.setOpBuyerOpenId(aliPayParam.getOpenId()); + model.setTimeExpire(PayUtil.getAliTimeExpire(payOrder.getExpiredTime())); + // 是否分账 + if (payOrder.getAllocation()){ + ExtendParams extendParams = new ExtendParams(); + extendParams.setRoyaltyFreeze(Boolean.TRUE.toString()); + model.setExtendParams(extendParams); + } + request.setBizModel(model); + try { + AlipayTradeCreateResponse response = alipayClient.execute(request); + this.verifyErrorMsg(response); + // my.tradePay使用支付宝交易号调起支付 + return response.getTradeNo(); + } catch (AlipayApiException e) { + log.error("支付宝JsApi支付失败", e); + throw new PayFailureException("支付宝JsApi支付失败"); + } + } + /** * 二维码支付(扫码支付) */ + @SneakyThrows public String qrCodePay(String amount, PayOrder payOrder, AliPayConfig alipayConfig) { + // 获取支付宝客户端 + AlipayClient alipayClient = aliPayConfigService.getAlipayClient(alipayConfig); + AlipayTradePrecreateModel model = new AlipayTradePrecreateModel(); model.setSubject(payOrder.getTitle()); model.setOutTradeNo(payOrder.getOrderNo()); @@ -215,14 +274,16 @@ public class AliPayService { // 是否分账 if (payOrder.getAllocation()){ ExtendParams extendParams = new ExtendParams(); - extendParams.setRoyaltyFreeze("true"); + extendParams.setRoyaltyFreeze(Boolean.TRUE.toString()); model.setExtendParams(extendParams); } // 过期时间 model.setTimeExpire(PayUtil.getAliTimeExpire(payOrder.getExpiredTime())); - + AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest(); + request.setBizModel(model); + request.setNotifyUrl(alipayConfig.getNotifyUrl()); try { - AlipayTradePrecreateResponse response = AliPayApi.tradePrecreatePayToResponse(model, alipayConfig.getNotifyUrl()); + AlipayTradePrecreateResponse response = alipayClient.execute(request); this.verifyErrorMsg(response); return response.getQrCode(); } @@ -235,9 +296,12 @@ public class AliPayService { /** * 付款码支付 */ + @SneakyThrows public void barCode(String amount, PayOrder payOrder, AliPayParam aliPayParam, AliPayConfig alipayConfig) { - PayLocal payInfo = PaymentContextLocal.get().getPayInfo(); + // 获取支付宝客户端 + AlipayClient alipayClient = aliPayConfigService.getAlipayClient(alipayConfig); + PayLocal payInfo = PaymentContextLocal.get().getPayInfo(); AlipayTradePayModel model = new AlipayTradePayModel(); model.setSubject(payOrder.getTitle()); model.setOutTradeNo(payOrder.getOrderNo()); @@ -246,14 +310,17 @@ public class AliPayService { // 是否分账 if (payOrder.getAllocation()){ ExtendParams extendParams = new ExtendParams(); - extendParams.setRoyaltyFreeze("true"); + extendParams.setRoyaltyFreeze(Boolean.TRUE.toString()); model.setExtendParams(extendParams); } // 过期时间 model.setTimeExpire(PayUtil.getAliTimeExpire(payOrder.getExpiredTime())); model.setTotalAmount(amount); + AlipayTradePayRequest request = new AlipayTradePayRequest(); + request.setBizModel(model); + request.setNotifyUrl(alipayConfig.getNotifyUrl()); try { - AlipayTradePayResponse response = AliPayApi.tradePayToResponse(model, alipayConfig.getNotifyUrl()); + AlipayTradePayResponse response = alipayClient.execute(request); // 支付成功处理 金额2000以下免密支付, 记录支付完成相关信息 if (Objects.equals(response.getCode(), AliPayCode.SUCCESS)) { Date gmtPayment = response.getGmtPayment(); diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/core/extra/AliPayAuthService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/core/extra/AliPayAuthService.java index 9ca341d4..787e4a24 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/core/extra/AliPayAuthService.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/daxpay/single/service/core/extra/AliPayAuthService.java @@ -11,8 +11,6 @@ import cn.daxpay.single.service.dto.extra.OpenIdResult; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import com.alipay.api.AlipayClient; -import com.alipay.api.AlipayConfig; -import com.alipay.api.DefaultAlipayClient; import com.alipay.api.request.AlipaySystemOauthTokenRequest; import com.alipay.api.response.AlipaySystemOauthTokenResponse; import lombok.RequiredArgsConstructor; @@ -93,7 +91,7 @@ public class AliPayAuthService { @SneakyThrows public String getOpenId(String authCode) { // 初始化SDK - AlipayClient alipayClient = new DefaultAlipayClient(this.getAlipayConfig()); + AlipayClient alipayClient = aliPayConfigService.getAlipayClient(); // 构造请求参数以调用接口 AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest(); // 设置授权码 @@ -105,26 +103,6 @@ public class AliPayAuthService { log.warn("获取支付宝OpenId失败,原因:{}", response.getSubMsg()); throw new BizException("获取支付宝OpenId失败"); } - return response.getOpenId(); } - - /** - * 获取支付宝SDK的配置 - */ - private AlipayConfig getAlipayConfig(){ - AliPayConfig aliPayConfig = aliPayConfigService.getConfig(); - String privateKey = aliPayConfig.getPrivateKey(); - String alipayPublicKey =aliPayConfig.getAlipayPublicKey(); - AlipayConfig alipayConfig = new AlipayConfig(); - alipayConfig.setServerUrl(aliPayConfig.getServerUrl()); - alipayConfig.setAppId(aliPayConfig.getAppId()); - alipayConfig.setPrivateKey(privateKey); - alipayConfig.setFormat("json"); - alipayConfig.setAlipayPublicKey(alipayPublicKey); - alipayConfig.setCharset("UTF-8"); - alipayConfig.setSignType(aliPayConfig.getSignType()); - return alipayConfig; - } - }