Commit 1ed6656bbb103133dba4be65ee0875c4550d6550
1 parent
23d8da74
完成对微信公众号支付的封装
Showing
15 changed files
with
423 additions
and
67 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/io/FileUtils.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.common.util.io; | |
| 2 | + | |
| 3 | +import cn.hutool.core.io.FileUtil; | |
| 4 | +import cn.hutool.core.util.IdUtil; | |
| 5 | +import lombok.SneakyThrows; | |
| 6 | + | |
| 7 | +import java.io.File; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * 文件工具类 | |
| 11 | + * | |
| 12 | + * @author 芋道源码 | |
| 13 | + */ | |
| 14 | +public class FileUtils { | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 创建临时文件 | |
| 18 | + * 该文件会在 JVM 退出时,进行删除 | |
| 19 | + * | |
| 20 | + * @param data 文件内容 | |
| 21 | + * @return 文件 | |
| 22 | + */ | |
| 23 | + @SneakyThrows | |
| 24 | + public static File createTempFile(String data) { | |
| 25 | + // 创建文件,通过 UUID 保证唯一 | |
| 26 | + File file = File.createTempFile(IdUtil.simpleUUID(), null); | |
| 27 | + // 标记 JVM 退出时,自动删除 | |
| 28 | + file.deleteOnExit(); | |
| 29 | + // 写入内容 | |
| 30 | + FileUtil.writeUtf8String(data, file); | |
| 31 | + return file; | |
| 32 | + } | |
| 33 | + | |
| 34 | +} | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml
| ... | ... | @@ -11,7 +11,10 @@ |
| 11 | 11 | |
| 12 | 12 | <artifactId>yudao-spring-boot-starter-biz-pay</artifactId> |
| 13 | 13 | <name>${artifactId}</name> |
| 14 | - <description>支付拓展,基于 IJPay 简单封装,支持微信、支付宝等常见支付渠道</description> | |
| 14 | + <description>支付拓展,接入国内多个支付渠道 | |
| 15 | + 1. 支付宝,基于官方 SDK 接入 | |
| 16 | + 2. 微信支付,基于 weixin-java-pay 接入 | |
| 17 | + </description> | |
| 15 | 18 | |
| 16 | 19 | <dependencies> |
| 17 | 20 | <dependency> |
| ... | ... | @@ -34,17 +37,36 @@ |
| 34 | 37 | <artifactId>slf4j-api</artifactId> |
| 35 | 38 | </dependency> |
| 36 | 39 | |
| 37 | - <!-- 三方云服务相关 --> | |
| 38 | 40 | <dependency> |
| 39 | - <groupId>com.github.javen205</groupId> | |
| 40 | - <artifactId>IJPay-AliPay</artifactId> | |
| 41 | - <version>2.7.8</version> | |
| 41 | + <groupId>com.fasterxml.jackson.core</groupId> | |
| 42 | + <artifactId>jackson-databind</artifactId> | |
| 42 | 43 | </dependency> |
| 43 | 44 | <dependency> |
| 44 | - <groupId>com.github.javen205</groupId> | |
| 45 | - <artifactId>IJPay-WxPay</artifactId> | |
| 46 | - <version>2.7.8</version> | |
| 45 | + <groupId>com.fasterxml.jackson.core</groupId> | |
| 46 | + <artifactId>jackson-core</artifactId> | |
| 47 | 47 | </dependency> |
| 48 | 48 | |
| 49 | + <!-- 三方云服务相关 --> | |
| 50 | +<!-- <dependency>--> | |
| 51 | +<!-- <groupId>com.github.javen205</groupId>--> | |
| 52 | +<!-- <artifactId>IJPay-AliPay</artifactId>--> | |
| 53 | +<!-- <version>2.7.8</version>--> | |
| 54 | +<!-- </dependency>--> | |
| 55 | +<!-- <dependency>--> | |
| 56 | +<!-- <groupId>com.github.javen205</groupId>--> | |
| 57 | +<!-- <artifactId>IJPay-WxPay</artifactId>--> | |
| 58 | +<!-- <version>2.7.8</version>--> | |
| 59 | +<!-- </dependency>--> | |
| 60 | + <dependency> | |
| 61 | + <groupId>com.alipay.sdk</groupId> | |
| 62 | + <artifactId>alipay-sdk-java</artifactId> | |
| 63 | + <version>4.17.9.ALL</version> | |
| 64 | + </dependency> | |
| 65 | + <dependency> | |
| 66 | + <groupId>com.github.binarywang</groupId> | |
| 67 | + <artifactId>weixin-java-pay</artifactId> | |
| 68 | + <version>4.1.9.B</version> | |
| 69 | + </dependency> | |
| 70 | + <!-- TODO 芋艿:清理 --> | |
| 49 | 71 | </dependencies> |
| 50 | 72 | </project> | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayCodeMapping.java renamed to yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/AbstractPayCodeMapping.java
| ... | ... | @@ -2,8 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.exception.ErrorCode; |
| 4 | 4 | import cn.iocoder.yudao.framework.pay.core.enums.PayFrameworkErrorCodeConstants; |
| 5 | - | |
| 6 | -import java.util.function.Function; | |
| 5 | +import lombok.extern.slf4j.Slf4j; | |
| 7 | 6 | |
| 8 | 7 | /** |
| 9 | 8 | * 将 API 的错误码,转换为通用的错误码 |
| ... | ... | @@ -13,5 +12,22 @@ import java.util.function.Function; |
| 13 | 12 | * |
| 14 | 13 | * @author 芋道源码 |
| 15 | 14 | */ |
| 16 | -public interface PayCodeMapping extends Function<String, ErrorCode> { | |
| 15 | +@Slf4j | |
| 16 | +public abstract class AbstractPayCodeMapping { | |
| 17 | + | |
| 18 | + public final ErrorCode apply(String apiCode, String apiMsg) { | |
| 19 | + if (apiCode == null) { | |
| 20 | + log.error("[apply][API 错误码为空,请排查]"); | |
| 21 | + return PayFrameworkErrorCodeConstants.EXCEPTION; | |
| 22 | + } | |
| 23 | + ErrorCode errorCode = this.apply0(apiCode, apiMsg); | |
| 24 | + if (errorCode == null) { | |
| 25 | + log.error("[apply][API 错误码({}) 错误提示({}) 无法匹配]", apiCode, apiMsg); | |
| 26 | + return PayFrameworkErrorCodeConstants.PAY_UNKNOWN; | |
| 27 | + } | |
| 28 | + return errorCode; | |
| 29 | + } | |
| 30 | + | |
| 31 | + protected abstract ErrorCode apply0(String apiCode, String apiMsg); | |
| 32 | + | |
| 17 | 33 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayCommonResult.java
| ... | ... | @@ -35,16 +35,13 @@ public class PayCommonResult<T> extends CommonResult<T> { |
| 35 | 35 | private PayCommonResult() { |
| 36 | 36 | } |
| 37 | 37 | |
| 38 | - public static <T> PayCommonResult<T> build(String apiCode, String apiMsg, T data, PayCodeMapping codeMapping) { | |
| 38 | + public static <T> PayCommonResult<T> build(String apiCode, String apiMsg, T data, AbstractPayCodeMapping codeMapping) { | |
| 39 | 39 | Assert.notNull(codeMapping, "参数 codeMapping 不能为空"); |
| 40 | 40 | PayCommonResult<T> result = new PayCommonResult<T>().setApiCode(apiCode).setApiMsg(apiMsg); |
| 41 | 41 | result.setData(data); |
| 42 | 42 | // 翻译错误码 |
| 43 | 43 | if (codeMapping != null) { |
| 44 | - ErrorCode errorCode = codeMapping.apply(apiCode); | |
| 45 | - if (errorCode == null) { | |
| 46 | - errorCode = PayFrameworkErrorCodeConstants.EXCEPTION; | |
| 47 | - } | |
| 44 | + ErrorCode errorCode = codeMapping.apply(apiCode, apiMsg); | |
| 48 | 45 | result.setCode(errorCode.getCode()).setMsg(errorCode.getMsg()); |
| 49 | 46 | } |
| 50 | 47 | return result; | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderUnifiedReqDTO.java
| ... | ... | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.dto; |
| 2 | 2 | |
| 3 | 3 | import lombok.Data; |
| 4 | 4 | import org.hibernate.validator.constraints.Length; |
| 5 | +import org.hibernate.validator.constraints.URL; | |
| 5 | 6 | |
| 6 | 7 | import javax.validation.constraints.DecimalMin; |
| 7 | 8 | import javax.validation.constraints.NotEmpty; |
| ... | ... | @@ -39,6 +40,12 @@ public class PayOrderUnifiedReqDTO { |
| 39 | 40 | @NotEmpty(message = "商品描述信息不能为空") |
| 40 | 41 | @Length(max = 128, message = "商品描述信息长度不能超过128") |
| 41 | 42 | private String body; |
| 43 | + /** | |
| 44 | + * 支付结果的回调地址 | |
| 45 | + */ | |
| 46 | + @NotEmpty(message = "支付结果的回调地址不能为空") | |
| 47 | + @URL(message = "支付结果的回调地址必须是 URL 格式") | |
| 48 | + private String notifyUrl; | |
| 42 | 49 | |
| 43 | 50 | // ========== 订单相关字段 ========== |
| 44 | 51 | |
| ... | ... | @@ -55,4 +62,7 @@ public class PayOrderUnifiedReqDTO { |
| 55 | 62 | @NotNull(message = "支付过期时间不能为空") |
| 56 | 63 | private Date expireTime; |
| 57 | 64 | |
| 65 | + // ========== 拓展参数 ========== | |
| 66 | + // TODO 芋艿:待完善 | |
| 67 | + | |
| 58 | 68 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
| ... | ... | @@ -2,7 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 4 | 4 | import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; |
| 5 | -import cn.iocoder.yudao.framework.pay.core.client.PayCodeMapping; | |
| 5 | +import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping; | |
| 6 | 6 | import lombok.extern.slf4j.Slf4j; |
| 7 | 7 | |
| 8 | 8 | /** |
| ... | ... | @@ -24,7 +24,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen |
| 24 | 24 | /** |
| 25 | 25 | * 错误码枚举类 |
| 26 | 26 | */ |
| 27 | - protected PayCodeMapping codeMapping; | |
| 27 | + protected AbstractPayCodeMapping codeMapping; | |
| 28 | 28 | /** |
| 29 | 29 | * 支付配置 |
| 30 | 30 | */ |
| ... | ... | @@ -34,7 +34,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen |
| 34 | 34 | return amount / 100.0; |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | - public AbstractPayClient(Long channelId, String channelCode, Config config, PayCodeMapping codeMapping) { | |
| 37 | + public AbstractPayClient(Long channelId, String channelCode, Config config, AbstractPayCodeMapping codeMapping) { | |
| 38 | 38 | this.channelId = channelId; |
| 39 | 39 | this.channelCode = channelCode; |
| 40 | 40 | this.codeMapping = codeMapping; | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayConfig.java renamed to yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayClientConfig.java
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayCodeMapping.java
| 1 | 1 | package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.exception.ErrorCode; |
| 4 | -import cn.iocoder.yudao.framework.pay.core.client.PayCodeMapping; | |
| 4 | +import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping; | |
| 5 | 5 | |
| 6 | -public class AlipayPayCodeMapping implements PayCodeMapping { | |
| 6 | +/** | |
| 7 | + * 支付宝的 PayCodeMapping 实现类 | |
| 8 | + * | |
| 9 | + * @author 芋道源码 | |
| 10 | + */ | |
| 11 | +public class AlipayPayCodeMapping extends AbstractPayCodeMapping { | |
| 7 | 12 | |
| 8 | 13 | @Override |
| 9 | - public ErrorCode apply(String s) { | |
| 14 | + protected ErrorCode apply0(String apiCode, String apiMsg) { | |
| 10 | 15 | return null; |
| 11 | 16 | } |
| 12 | 17 | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java
| ... | ... | @@ -12,6 +12,9 @@ import com.alipay.api.domain.AlipayTradePrecreateModel; |
| 12 | 12 | import com.alipay.api.request.AlipayTradePrecreateRequest; |
| 13 | 13 | import com.alipay.api.response.AlipayTradePrecreateResponse; |
| 14 | 14 | import lombok.SneakyThrows; |
| 15 | +import lombok.extern.slf4j.Slf4j; | |
| 16 | + | |
| 17 | +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | |
| 15 | 18 | |
| 16 | 19 | /** |
| 17 | 20 | * 支付宝【扫码支付】的 PayClient 实现类 |
| ... | ... | @@ -19,11 +22,12 @@ import lombok.SneakyThrows; |
| 19 | 22 | * |
| 20 | 23 | * @author 芋道源码 |
| 21 | 24 | */ |
| 22 | -public class AlipayQrPayClient extends AbstractPayClient<AlipayPayConfig> { | |
| 25 | +@Slf4j | |
| 26 | +public class AlipayQrPayClient extends AbstractPayClient<AlipayPayClientConfig> { | |
| 23 | 27 | |
| 24 | 28 | private DefaultAlipayClient client; |
| 25 | 29 | |
| 26 | - public AlipayQrPayClient(Long channelId, String channelCode, AlipayPayConfig config) { | |
| 30 | + public AlipayQrPayClient(Long channelId, String channelCode, AlipayPayClientConfig config) { | |
| 27 | 31 | super(channelId, channelCode, config, new AlipayPayCodeMapping()); |
| 28 | 32 | } |
| 29 | 33 | |
| ... | ... | @@ -32,17 +36,18 @@ public class AlipayQrPayClient extends AbstractPayClient<AlipayPayConfig> { |
| 32 | 36 | protected void doInit() { |
| 33 | 37 | AlipayConfig alipayConfig = new AlipayConfig(); |
| 34 | 38 | BeanUtil.copyProperties(config, alipayConfig, false); |
| 39 | + // 真实客户端 | |
| 35 | 40 | this.client = new DefaultAlipayClient(alipayConfig); |
| 36 | 41 | } |
| 37 | 42 | |
| 38 | 43 | @Override |
| 39 | - public CommonResult<Object> unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { | |
| 44 | + public CommonResult<AlipayTradePrecreateResponse> unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { | |
| 40 | 45 | // 构建 AlipayTradePrecreateModel 请求 |
| 41 | 46 | AlipayTradePrecreateModel model = new AlipayTradePrecreateModel(); |
| 42 | 47 | model.setOutTradeNo(reqDTO.getMerchantOrderId()); |
| 43 | 48 | model.setSubject(reqDTO.getSubject()); |
| 44 | 49 | model.setBody(reqDTO.getBody()); |
| 45 | - model.setTotalAmount(calculateAmount(reqDTO.getAmount()).toString()); | |
| 50 | + model.setTotalAmount(calculateAmount(reqDTO.getAmount()).toString()); // 单位:元 | |
| 46 | 51 | // TODO 芋艿:clientIp + expireTime |
| 47 | 52 | // 构建 AlipayTradePrecreateRequest |
| 48 | 53 | AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest(); |
| ... | ... | @@ -53,6 +58,7 @@ public class AlipayQrPayClient extends AbstractPayClient<AlipayPayConfig> { |
| 53 | 58 | try { |
| 54 | 59 | response = client.execute(request); |
| 55 | 60 | } catch (AlipayApiException e) { |
| 61 | + log.error("[unifiedOrder][request({}) 发起支付失败]", toJsonString(reqDTO), e); | |
| 56 | 62 | return PayCommonResult.build(e.getErrCode(), e.getErrMsg(), null, codeMapping); |
| 57 | 63 | } |
| 58 | 64 | |
| ... | ... | @@ -64,10 +70,10 @@ public class AlipayQrPayClient extends AbstractPayClient<AlipayPayConfig> { |
| 64 | 70 | } |
| 65 | 71 | |
| 66 | 72 | public static void main(String[] args) { |
| 67 | - AlipayPayConfig config = new AlipayPayConfig(); | |
| 73 | + AlipayPayClientConfig config = new AlipayPayClientConfig(); | |
| 68 | 74 | config.setAppId("2021000118634035"); |
| 69 | - config.setServerUrl(AlipayPayConfig.SERVER_URL_SANDBOX); | |
| 70 | - config.setSignType(AlipayPayConfig.SIGN_TYPE_DEFAULT); | |
| 75 | + config.setServerUrl(AlipayPayClientConfig.SERVER_URL_SANDBOX); | |
| 76 | + config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT); | |
| 71 | 77 | config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8="); |
| 72 | 78 | config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB"); |
| 73 | 79 | AlipayQrPayClient client = new AlipayQrPayClient(1L, "biu", config); |
| ... | ... | @@ -79,4 +85,5 @@ public class AlipayQrPayClient extends AbstractPayClient<AlipayPayConfig> { |
| 79 | 85 | reqDTO.setMerchantOrderId(String.valueOf(System.currentTimeMillis())); |
| 80 | 86 | client.unifiedOrder(reqDTO); |
| 81 | 87 | } |
| 88 | + | |
| 82 | 89 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java
| ... | ... | @@ -19,11 +19,11 @@ import lombok.SneakyThrows; |
| 19 | 19 | * |
| 20 | 20 | * @author 芋道源码 |
| 21 | 21 | */ |
| 22 | -public class AlipayWapPayClient extends AbstractPayClient<AlipayPayConfig> { | |
| 22 | +public class AlipayWapPayClient extends AbstractPayClient<AlipayPayClientConfig> { | |
| 23 | 23 | |
| 24 | 24 | private DefaultAlipayClient client; |
| 25 | 25 | |
| 26 | - public AlipayWapPayClient(Long channelId, String channelCode, AlipayPayConfig config) { | |
| 26 | + public AlipayWapPayClient(Long channelId, String channelCode, AlipayPayClientConfig config) { | |
| 27 | 27 | super(channelId, channelCode, config, new AlipayPayCodeMapping()); |
| 28 | 28 | } |
| 29 | 29 | |
| ... | ... | @@ -36,7 +36,7 @@ public class AlipayWapPayClient extends AbstractPayClient<AlipayPayConfig> { |
| 36 | 36 | } |
| 37 | 37 | |
| 38 | 38 | @Override |
| 39 | - public CommonResult<Object> unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { | |
| 39 | + public CommonResult<AlipayTradeWapPayResponse> unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { | |
| 40 | 40 | // 构建 AlipayTradeWapPayModel 请求 |
| 41 | 41 | AlipayTradeWapPayModel model = new AlipayTradeWapPayModel(); |
| 42 | 42 | model.setOutTradeNo(reqDTO.getMerchantOrderId()); |
| ... | ... | @@ -65,10 +65,10 @@ public class AlipayWapPayClient extends AbstractPayClient<AlipayPayConfig> { |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | 67 | public static void main(String[] args) { |
| 68 | - AlipayPayConfig config = new AlipayPayConfig(); | |
| 68 | + AlipayPayClientConfig config = new AlipayPayClientConfig(); | |
| 69 | 69 | config.setAppId("2021000118634035"); |
| 70 | - config.setServerUrl(AlipayPayConfig.SERVER_URL_SANDBOX); | |
| 71 | - config.setSignType(AlipayPayConfig.SIGN_TYPE_DEFAULT); | |
| 70 | + config.setServerUrl(AlipayPayClientConfig.SERVER_URL_SANDBOX); | |
| 71 | + config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT); | |
| 72 | 72 | config.setPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHsEV1cDupwJv890x84qbppUtRIfhaKSwSVN0thCcsDCaAsGR5MZslDkO8NCT9V4r2SVXjyY7eJUZlZd1M0C8T01Tg4UOx5LUbic0O3A1uJMy6V1n9IyYwbAW3AEZhBd5bSbPgrqvmv3NeWSTQT6Anxnllf+2iDH6zyA2fPl7cYyQtbZoDJQFGqr4F+cGh2R6akzRKNoBkAeMYwoY6es2lX8sJxCVPWUmxNUoL3tScwlSpd7Bxw0q9c/X01jMwuQ0+Va358zgFiGERTE6yD01eu40OBDXOYO3z++y+TAYHlQQ2toMO63trepo88X3xV3R44/1DH+k2pAm2IF5ixiLrAgMBAAECggEAPx3SoXcseaD7rmcGcE0p4SMfbsUDdkUSmBBbtfF0GzwnqNLkWa+mgE0rWt9SmXngTQH97vByAYmLPl1s3G82ht1V7Sk7yQMe74lhFllr8eEyTjeVx3dTK1EEM4TwN+936DTXdFsr4TELJEcJJdD0KaxcCcfBLRDs2wnitEFZ9N+GoZybVmY8w0e0MI7PLObUZ2l0X4RurQnfG9ZxjXjC7PkeMVv7cGGylpNFi3BbvkRhdhLPDC2E6wqnr9e7zk+hiENivAezXrtxtwKovzCtnWJ1r0IO14Rh47H509Ic0wFnj+o5YyUL4LdmpL7yaaH6fM7zcSLFjNZPHvZCKPwYcQKBgQDQFho98QvnL8ex4v6cry4VitGpjSXm1qP3vmMQk4rTsn8iPWtcxPjqGEqOQJjdi4Mi0VZKQOLFwlH0kl95wNrD/isJ4O1yeYfX7YAXApzHqYNINzM79HemO3Yx1qLMW3okRFJ9pPRzbQ9qkTpsaegsmyX316zOBhzGRYjKbutTYwKBgQCm7phr9XdFW5Vh+XR90mVs483nrLmMiDKg7YKxSLJ8amiDjzPejCn7i95Hah08P+2MIZLIPbh2VLacczR6ltRRzN5bg5etFuqSgfkuHyxpoDmpjbe08+Q2h8JBYqcC5Nhv1AKU4iOUhVLHo/FBAQliMcGc/J3eiYTFC7EsNx382QKBgClb20doe7cttgFTXswBvaUmfFm45kmla924B7SpvrQpDD/f+VDtDZRp05fGmxuduSjYdtA3aVtpLiTwWu22OUUvZZqHDGruYOO4Hvdz23mL5b4ayqImCwoNU4bAZIc9v18p/UNf3/55NNE3oGcf/bev9rH2OjCQ4nM+Ktwhg8CFAoGACSgvbkShzUkv0ZcIf9ppu+ZnJh1AdGgINvGwaJ8vQ0nm/8h8NOoFZ4oNoGc+wU5Ubops7dUM6FjPR5e+OjdJ4E7Xp7d5O4J1TaIZlCEbo5OpdhaTDDcQvrkFu+Z4eN0qzj+YAKjDAOOrXc4tbr5q0FsgXscwtcNfaBuzFVTUrUkCgYEAwzPnMNhWG3zOWLUs2QFA2GP4Y+J8cpUYfj6pbKKzeLwyG9qBwF1NJpN8m+q9q7V9P2LY+9Lp9e1mGsGeqt5HMEA3P6vIpcqLJLqE/4PBLLRzfccTcmqb1m71+erxTRhHBRkGS+I7dZEb3olQfnS1Y1tpMBxiwYwR3LW4oXuJwj8="); |
| 73 | 73 | config.setAlipayPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnq90KnF4dTnlzzmxpujbI05OYqi5WxAS6cL0gnZFv2gK51HExF8v/BaP7P979PhFMgWTqmOOI+Dtno5s+yD09XTY1WkshbLk6i4g2Xlr8fyW9ODnkU88RI2w9UdPhQU4cPPwBNlrsYhKkVK2OxwM3kFqjoBBY0CZoZCsSQ3LDH5WeZqPArlsS6xa2zqJBuuoKjMrdpELl3eXSjP8K54eDJCbeetCZNKWLL3DPahTPB7LZikfYmslb0QUvCgGapD0xkS7eVq70NaL1G57MWABs4tbfWgxike4Daj3EfUrzIVspQxj7w8HEj9WozJPgL88kSJSits0pqD3n5r8HSuseQIDAQAB"); |
| 74 | 74 | AlipayWapPayClient client = new AlipayWapPayClient(1L, "biubiubiu", config); | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXCodeMapping.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.pay.core.client.impl.wx; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.exception.ErrorCode; | |
| 4 | +import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; | |
| 5 | +import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping; | |
| 6 | + | |
| 7 | +import java.util.Objects; | |
| 8 | + | |
| 9 | +import static cn.iocoder.yudao.framework.pay.core.enums.PayFrameworkErrorCodeConstants.*; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * 微信支付 PayCodeMapping 实现类 | |
| 13 | + * | |
| 14 | + * @author 芋道源码 | |
| 15 | + */ | |
| 16 | +public class WXCodeMapping extends AbstractPayCodeMapping { | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * 错误码 - 成功 | |
| 20 | + * 由于 weixin-java-pay 封装的 Result 未返回 code,所以自己定义下 | |
| 21 | + */ | |
| 22 | + public static final String CODE_SUCCESS = "SUCCESS"; | |
| 23 | + /** | |
| 24 | + * 错误提示 - 成功 | |
| 25 | + */ | |
| 26 | + public static final String MESSAGE_SUCCESS = "成功"; | |
| 27 | + | |
| 28 | + @Override | |
| 29 | + protected ErrorCode apply0(String apiCode, String apiMsg) { | |
| 30 | + if (Objects.equals(apiCode, CODE_SUCCESS)) { | |
| 31 | + return GlobalErrorCodeConstants.SUCCESS; | |
| 32 | + } | |
| 33 | + if (Objects.equals(apiCode, "FAIL")) { | |
| 34 | + if (Objects.equals(apiMsg, "AppID不存在,请检查后再试")) { | |
| 35 | + return PAY_CONFIG_APP_ID_ERROR; | |
| 36 | + } | |
| 37 | + if (Objects.equals(apiMsg, "签名错误,请检查后再试") | |
| 38 | + || Objects.equals(apiMsg, "签名错误")) { | |
| 39 | + return PAY_CONFIG_SIGN_ERROR; | |
| 40 | + } | |
| 41 | + } | |
| 42 | + if (Objects.equals(apiCode, "PARAM_ERROR")) { | |
| 43 | + if (Objects.equals(apiMsg, "无效的openid")) { | |
| 44 | + return PAY_OPENID_ERROR; | |
| 45 | + } | |
| 46 | + } | |
| 47 | + return null; | |
| 48 | + } | |
| 49 | + | |
| 50 | +} | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPayClientConfig.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.pay.core.client.impl.wx; | |
| 2 | + | |
| 3 | +import cn.hutool.core.io.IoUtil; | |
| 4 | +import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +import java.io.FileInputStream; | |
| 8 | +import java.io.FileNotFoundException; | |
| 9 | + | |
| 10 | +// TODO 芋艿:参数校验 | |
| 11 | +/** | |
| 12 | + * 微信支付的 PayClientConfig 实现类 | |
| 13 | + * 属性主要来自 {@link com.github.binarywang.wxpay.config.WxPayConfig} 的必要属性 | |
| 14 | + * | |
| 15 | + * @author 芋道源码 | |
| 16 | + */ | |
| 17 | +@Data | |
| 18 | +public class WXPayClientConfig implements PayClientConfig { | |
| 19 | + | |
| 20 | + // TODO 芋艿:V2 or V3 客户端 | |
| 21 | + /** | |
| 22 | + * API 版本 - V2 | |
| 23 | + * | |
| 24 | + * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_1 | |
| 25 | + */ | |
| 26 | + public static final String API_VERSION_V2 = "v2"; | |
| 27 | + /** | |
| 28 | + * API 版本 - V3 | |
| 29 | + * | |
| 30 | + * https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay-1.shtml | |
| 31 | + */ | |
| 32 | + public static final String API_VERSION_V3 = "v3"; | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * 公众号或者小程序的 appid | |
| 36 | + */ | |
| 37 | + private String appId; | |
| 38 | + /** | |
| 39 | + * 商户号 | |
| 40 | + */ | |
| 41 | + private String mchId; | |
| 42 | + /** | |
| 43 | + * API 版本 | |
| 44 | + */ | |
| 45 | + private String apiVersion; | |
| 46 | + | |
| 47 | + // ========== V2 版本的参数 ========== | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * 商户密钥 | |
| 51 | + */ | |
| 52 | + private String mchKey; | |
| 53 | +// /** | |
| 54 | +// * apiclient_cert.p12 证书文件的绝对路径或者以 classpath: 开头的类路径. | |
| 55 | +// * 对应的字符串 | |
| 56 | +// * | |
| 57 | +// * 注意,可通过 {@link #main(String[])} 读取 | |
| 58 | +// */ | |
| 59 | +// private String keyContent; | |
| 60 | + | |
| 61 | + // ========== V3 版本的参数 ========== | |
| 62 | + /** | |
| 63 | + * apiclient_key.pem 证书文件的绝对路径或者以 classpath: 开头的类路径. | |
| 64 | + * 对应的字符串 | |
| 65 | + * | |
| 66 | + * 注意,可通过 {@link #main(String[])} 读取 | |
| 67 | + */ | |
| 68 | + private String privateKeyContent; | |
| 69 | + /** | |
| 70 | + * apiclient_cert.pem 证书文件的绝对路径或者以 classpath: 开头的类路径. | |
| 71 | + * 对应的字符串 | |
| 72 | + * | |
| 73 | + * 注意,可通过 {@link #main(String[])} 读取 | |
| 74 | + */ | |
| 75 | + private String privateCertContent; | |
| 76 | + /** | |
| 77 | + * apiV3 秘钥值 | |
| 78 | + */ | |
| 79 | + private String apiV3Key; | |
| 80 | + | |
| 81 | + public static void main(String[] args) throws FileNotFoundException { | |
| 82 | + String path = "/Users/yunai/Downloads/wx_pay/apiclient_cert.p12"; | |
| 83 | +// String path = "/Users/yunai/Downloads/wx_pay/apiclient_key.pem"; | |
| 84 | +// String path = "/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"; | |
| 85 | + System.out.println(IoUtil.readUtf8(new FileInputStream(path))); | |
| 86 | + } | |
| 87 | + | |
| 88 | +} | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPubPayClient.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.pay.core.client.impl.wx; | |
| 2 | + | |
| 3 | +import cn.hutool.core.bean.BeanUtil; | |
| 4 | +import cn.hutool.core.date.DateUtil; | |
| 5 | +import cn.hutool.core.io.IoUtil; | |
| 6 | +import cn.hutool.core.util.StrUtil; | |
| 7 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 8 | +import cn.iocoder.yudao.framework.common.util.io.FileUtils; | |
| 9 | +import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; | |
| 10 | +import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; | |
| 11 | +import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; | |
| 12 | +import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; | |
| 13 | +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; | |
| 14 | +import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request; | |
| 15 | +import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result; | |
| 16 | +import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; | |
| 17 | +import com.github.binarywang.wxpay.config.WxPayConfig; | |
| 18 | +import com.github.binarywang.wxpay.constant.WxPayConstants; | |
| 19 | +import com.github.binarywang.wxpay.exception.WxPayException; | |
| 20 | +import com.github.binarywang.wxpay.service.WxPayService; | |
| 21 | +import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; | |
| 22 | +import lombok.extern.slf4j.Slf4j; | |
| 23 | + | |
| 24 | +import java.io.FileInputStream; | |
| 25 | +import java.io.FileNotFoundException; | |
| 26 | + | |
| 27 | +import static cn.hutool.core.util.ObjectUtil.defaultIfNull; | |
| 28 | +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | |
| 29 | +import static cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXCodeMapping.CODE_SUCCESS; | |
| 30 | +import static cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXCodeMapping.MESSAGE_SUCCESS; | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * 微信支付(公众号)的 PayClient 实现类 | |
| 34 | + * | |
| 35 | + * @author 芋道源码 | |
| 36 | + */ | |
| 37 | +@Slf4j | |
| 38 | +public class WXPubPayClient extends AbstractPayClient<WXPayClientConfig> { | |
| 39 | + | |
| 40 | + private WxPayService client; | |
| 41 | + | |
| 42 | + public WXPubPayClient(Long channelId, String channelCode, WXPayClientConfig config) { | |
| 43 | + super(channelId, channelCode, config, new WXCodeMapping()); | |
| 44 | + } | |
| 45 | + | |
| 46 | + @Override | |
| 47 | + protected void doInit() { | |
| 48 | + WxPayConfig payConfig = new WxPayConfig(); | |
| 49 | + BeanUtil.copyProperties(config, payConfig, "keyContent"); | |
| 50 | + payConfig.setTradeType(WxPayConstants.TradeType.JSAPI); // 设置使用 JS API 支付方式 | |
| 51 | +// if (StrUtil.isNotEmpty(config.getKeyContent())) { | |
| 52 | +// payConfig.setKeyContent(config.getKeyContent().getBytes(StandardCharsets.UTF_8)); | |
| 53 | +// } | |
| 54 | + if (StrUtil.isNotEmpty(config.getPrivateKeyContent())) { | |
| 55 | + // weixin-pay-java 存在 BUG,无法直接设置内容,所以创建临时文件来解决 | |
| 56 | + payConfig.setPrivateKeyPath(FileUtils.createTempFile(config.getPrivateKeyContent()).getPath()); | |
| 57 | + } | |
| 58 | + if (StrUtil.isNotEmpty(config.getPrivateCertContent())) { | |
| 59 | + // weixin-pay-java 存在 BUG,无法直接设置内容,所以创建临时文件来解决 | |
| 60 | + payConfig.setPrivateCertPath(FileUtils.createTempFile(config.getPrivateCertContent()).getPath()); | |
| 61 | + } | |
| 62 | + // 真实客户端 | |
| 63 | + this.client = new WxPayServiceImpl(); | |
| 64 | + client.setConfig(payConfig); | |
| 65 | + } | |
| 66 | + | |
| 67 | + @Override | |
| 68 | + public CommonResult<WxPayMpOrderResult> unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { | |
| 69 | + WxPayMpOrderResult response; | |
| 70 | + try { | |
| 71 | + switch (config.getApiVersion()) { | |
| 72 | + case WXPayClientConfig.API_VERSION_V2: | |
| 73 | + response = this.unifiedOrderV2(reqDTO); | |
| 74 | + break; | |
| 75 | + case WXPayClientConfig.API_VERSION_V3: | |
| 76 | + WxPayUnifiedOrderV3Result.JsapiResult responseV3 = this.unifiedOrderV3(reqDTO); | |
| 77 | + // 将 V3 的结果,统一转换成 V2。返回的字段是一致的 | |
| 78 | + response = new WxPayMpOrderResult(); | |
| 79 | + BeanUtil.copyProperties(responseV3, response, true); | |
| 80 | + break; | |
| 81 | + default: | |
| 82 | + throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion())); | |
| 83 | + } | |
| 84 | + } catch (WxPayException e) { | |
| 85 | + log.error("[unifiedOrder][request({}) 发起支付失败,原因({})]", toJsonString(reqDTO), e); | |
| 86 | + return PayCommonResult.build(defaultIfNull(e.getErrCode(), e.getReturnCode()), | |
| 87 | + defaultIfNull(e.getErrCodeDes(), e.getReturnMsg()),null, codeMapping); | |
| 88 | + } | |
| 89 | + return PayCommonResult.build(CODE_SUCCESS, MESSAGE_SUCCESS, response, codeMapping); | |
| 90 | + } | |
| 91 | + | |
| 92 | + private WxPayMpOrderResult unifiedOrderV2(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 93 | + // 构建 WxPayUnifiedOrderRequest 对象 | |
| 94 | + WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder() | |
| 95 | + .outTradeNo(reqDTO.getMerchantOrderId()) | |
| 96 | + // TODO 芋艿:貌似没 title? | |
| 97 | + .body(reqDTO.getBody()) | |
| 98 | + .totalFee(reqDTO.getAmount()) // 单位分 | |
| 99 | + .timeExpire(DateUtil.format(reqDTO.getExpireTime(), "yyyyMMddHHmmss")) | |
| 100 | + .spbillCreateIp(reqDTO.getClientIp()) | |
| 101 | + .openid("ockUAwIZ-0OeMZl9ogcZ4ILrGba0") // TODO 芋艿:先随便写死 | |
| 102 | + .notifyUrl(reqDTO.getNotifyUrl()) | |
| 103 | + .build(); | |
| 104 | + // 执行请求 | |
| 105 | + return client.createOrder(request); | |
| 106 | + } | |
| 107 | + | |
| 108 | + private WxPayUnifiedOrderV3Result.JsapiResult unifiedOrderV3(PayOrderUnifiedReqDTO reqDTO) throws WxPayException { | |
| 109 | + // 构建 WxPayUnifiedOrderRequest 对象 | |
| 110 | + WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request(); | |
| 111 | + request.setOutTradeNo(reqDTO.getMerchantOrderId()); | |
| 112 | + // TODO 芋艿:貌似没 title? | |
| 113 | + request.setDescription(reqDTO.getBody()); | |
| 114 | + request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getAmount())); // 单位分 | |
| 115 | + request.setTimeExpire(DateUtil.format(reqDTO.getExpireTime(), "yyyyMMddHHmmss")); | |
| 116 | + request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid("ockUAwIZ-0OeMZl9ogcZ4ILrGba0")); // TODO 芋艿:先随便写死 | |
| 117 | + request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getClientIp())); | |
| 118 | + request.setNotifyUrl(reqDTO.getNotifyUrl()); | |
| 119 | + // 执行请求 | |
| 120 | + return client.createOrderV3(TradeTypeEnum.JSAPI, request); | |
| 121 | + } | |
| 122 | + | |
| 123 | + public static void main(String[] args) throws FileNotFoundException { | |
| 124 | + WXPayClientConfig config = new WXPayClientConfig(); | |
| 125 | + config.setAppId("wx041349c6f39b268b"); | |
| 126 | + config.setMchId("1545083881"); | |
| 127 | + config.setMchKey("0alL64UDQdlCwiKZ73ib7ypaIjMns06p"); | |
| 128 | + config.setApiVersion(WXPayClientConfig.API_VERSION_V3); | |
| 129 | +// config.setKeyContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_cert.p12"))); | |
| 130 | + config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_key.pem"))); | |
| 131 | + config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"))); | |
| 132 | + config.setApiV3Key("joerVi8y5DJ3o4ttA0o1uH47Xz1u2Ase"); | |
| 133 | + | |
| 134 | + WXPubPayClient client = new WXPubPayClient(1L, "biu", config); | |
| 135 | + client.init(); | |
| 136 | + | |
| 137 | + PayOrderUnifiedReqDTO reqDTO = new PayOrderUnifiedReqDTO(); | |
| 138 | + reqDTO.setAmount(123); | |
| 139 | + reqDTO.setSubject("IPhone 13"); | |
| 140 | + reqDTO.setBody("biubiubiu"); | |
| 141 | + reqDTO.setMerchantOrderId(String.valueOf(System.currentTimeMillis())); | |
| 142 | + reqDTO.setClientIp("127.0.0.1"); | |
| 143 | + reqDTO.setNotifyUrl("http://127.0.0.1:8080"); | |
| 144 | + CommonResult<WxPayMpOrderResult> result = client.unifiedOrder(reqDTO); | |
| 145 | + System.out.println(result); | |
| 146 | + } | |
| 147 | + | |
| 148 | +} | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayFrameworkErrorCodeConstants.java
| ... | ... | @@ -11,36 +11,15 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; |
| 11 | 11 | */ |
| 12 | 12 | public interface PayFrameworkErrorCodeConstants { |
| 13 | 13 | |
| 14 | - ErrorCode PAY_UNKNOWN = new ErrorCode(2001000000, "未知错误,需要解析"); | |
| 15 | - | |
| 16 | -// // ========== 权限 / 限流等相关 2001000100 ========== | |
| 17 | -// | |
| 18 | -// ErrorCode SMS_PERMISSION_DENY = new ErrorCode(2001000100, "没有发送短信的权限"); | |
| 19 | -// // 云片:可以配置 IP 白名单,只有在白名单中才可以发送短信 | |
| 20 | -// ErrorCode SMS_IP_DENY = new ErrorCode(2001000100, "IP 不允许发送短信"); | |
| 21 | -// | |
| 22 | -// // 阿里云:将短信发送频率限制在正常的业务限流范围内。默认短信验证码:使用同一签名,对同一个手机号验证码,支持 1 条 / 分钟,5 条 / 小时,累计 10 条 / 天。 | |
| 23 | -// ErrorCode SMS_SEND_BUSINESS_LIMIT_CONTROL = new ErrorCode(2001000102, "指定手机的发送限流"); | |
| 24 | -// // 阿里云:已经达到您在控制台设置的短信日发送量限额值。在国内消息设置 > 安全设置,修改发送总量阈值。 | |
| 25 | -// ErrorCode SMS_SEND_DAY_LIMIT_CONTROL = new ErrorCode(2001000103, "每天的发送限流"); | |
| 26 | -// | |
| 27 | -// ErrorCode SMS_SEND_CONTENT_INVALID = new ErrorCode(2001000104, "短信内容有敏感词"); | |
| 28 | -// | |
| 29 | -// // ========== 模板相关 2001000200 ========== | |
| 30 | -// ErrorCode SMS_TEMPLATE_INVALID = new ErrorCode(2001000200, "短信模板不合法"); // 包括短信模板不存在 | |
| 31 | -// ErrorCode SMS_TEMPLATE_PARAM_ERROR = new ErrorCode(2001000201, "模板参数不正确"); | |
| 32 | -// | |
| 33 | -// // ========== 签名相关 2001000300 ========== | |
| 34 | -// ErrorCode SMS_SIGN_INVALID = new ErrorCode(2001000300, "短信签名不可用"); | |
| 35 | -// | |
| 36 | -// // ========== 账户相关 2001000400 ========== | |
| 37 | -// ErrorCode SMS_ACCOUNT_MONEY_NOT_ENOUGH = new ErrorCode(2001000400, "账户余额不足"); | |
| 38 | -// ErrorCode SMS_ACCOUNT_INVALID = new ErrorCode(2001000401, "apiKey 不存在"); | |
| 39 | -// | |
| 40 | -// // ========== 其它相关 2001000900 开头 ========== | |
| 41 | -// ErrorCode SMS_API_PARAM_ERROR = new ErrorCode(2001000900, "请求参数缺失"); | |
| 42 | -// ErrorCode SMS_MOBILE_INVALID = new ErrorCode(2001000901, "手机格式不正确"); | |
| 43 | -// ErrorCode SMS_MOBILE_BLACK = new ErrorCode(2001000902, "手机号在黑名单中"); | |
| 14 | + ErrorCode PAY_UNKNOWN = new ErrorCode(2002000000, "未知错误,需要解析"); | |
| 15 | + | |
| 16 | + // ========== 配置相关相关 2002000100 ========== | |
| 17 | + ErrorCode PAY_CONFIG_APP_ID_ERROR = new ErrorCode(2002000100, "支付渠道 AppId 不正确"); | |
| 18 | + ErrorCode PAY_CONFIG_SIGN_ERROR = new ErrorCode(2002000100, "签名错误"); // 例如说,微信支付,配置错了 mchId 或者 mchKey | |
| 19 | + | |
| 20 | + | |
| 21 | + // ========== 其它相关 2002000900 开头 ========== | |
| 22 | + ErrorCode PAY_OPENID_ERROR = new ErrorCode(2002000900, "无效的 openid"); // 例如说,微信 openid 未授权过 | |
| 44 | 23 | |
| 45 | 24 | ErrorCode EXCEPTION = new ErrorCode(2002000999, "调用异常"); |
| 46 | 25 | ... | ... |