diff --git a/_doc/ChangeLog.md b/_doc/ChangeLog.md
index 8375bb8b6..619c7cade 100644
--- a/_doc/ChangeLog.md
+++ b/_doc/ChangeLog.md
@@ -1,21 +1,16 @@
# CHANGELOG
-## [v1.0.1] 支付之路: 多商户适配
-- 新增: 钱包支持多商户和多应用
-- 新增: 储值卡支持多商户和多应用
-- 新增: 网关同步记录进行保存
-- 新增: 钱包支持设置开通时的默认金额
-- 新增: 储值卡多卡支付演示
-- 优化: 结算台支持多商户
-- 优化: 重构支付消息通知结构, 使后期支持多种消息中间件
-- 优化: 拆分网关同步相关代码
-- 优化: 保存各渠道的支付单
-
-## [v1.0.0] 支付之路
-- 支持单渠道支付、聚合支付、组合支付、退款功能
-- 单渠道支付:支持支付宝、微信、现金、钱包、储值卡等多种支付方式
-- 聚合支付:支持微信或支付宝使用同一个码
-- 组合支付:支持多种同步支付和一个异步支付(微信、支付宝)进行组合支付
-- 支持退款:部分对款、全部退款等方式
-- 储值卡:支持单卡支付、多卡支付,退款时支持退款到原储值卡中,也支持将余额退到同一个卡上
-- 支付宝:支持web支付、wap支付、扫码支付、付款码支付、APP支付
-- 微信:wap支付、扫码支付、付款码支付、APP支付、公众号/小程序支付
+## [v2.0.0]
+- 支持请求参数签名和验签机制,已经支持SHA256和
+- 去除调用时的用户概念,作为独立的支付网关使用
+- 支持支付功能、已对支付宝、微信进行支持
+- 支持支付订单超时自动进行关闭
+- 支持支付订单关闭功能,关闭
+- 支持支付退款功能,可以进行全部退款或部分退款
+- 支持支付同步功能,通过同步接口可以获取第三方支付网关的状态
+- 支持支付和退款订单的修复功能,根据取第三方支付网关订单的状态,对订单进行修正,如支付同步、退款同步、消息回调等可触发
+- 部分支付对账功能,已经实现支付宝和微信对账单下载解析和保存的功能
+- 支持对各支付通道进行管理,包括是否启用、显示Logo图等
+- 支持对支付网关对外暴露的接口进行管理,支持启停用、是否验签、是否消息通知等功能
+- 组合支付已预先进行支持,支持一个异步支付+多个同步支付通道组合进行收单支付
+- 提供Java版本SDK,简化业务系统对支付网关的调用
+- 对回调记录、同步记录、修复记录、关闭记录、进行报错
diff --git a/_doc/Task.md b/_doc/Task.md
index 378123125..dae8d3b5f 100644
--- a/_doc/Task.md
+++ b/_doc/Task.md
@@ -1,10 +1,15 @@
+2.0.1 里程碑
+- 支持各类回调通知
+- 现金、钱包、储值卡功能进行重构
+-
+
2.0.0 重构进度
- 已经完成的
- [x] 参数签名和验签机制
- [x] 开放接口供第三方调用
- [x] 将零散的上下文对象进行抽取为统一的上下文对象
- [x] 拆分原有的策略类,实现粒度更细
- - [x] 去除用户概念,作为独立的支付网关使用, 不与其他系统产生耦合性
+ - [x] 去除用户概念,作为独立的支付网关使用,不与其他系统产生耦合性
- 2023-12-31:
- [x] 支付关闭相关逻辑
- [x] 各支付通道补充相关未实现的逻辑
@@ -55,7 +60,7 @@
- 2024-01-13:
- [x] (前端) 微信/支付宝支付通道配置
- [x] 支付通道支持停用
- - [x] 请求支付网关时区退款号以R开头, 用于与支付ID的区分
+ - [x] ~~请求支付网关时区退款号以R开头, 用于与支付ID的区分~~
- [x] (前端) 平台配置
- 2024-01-15:
- [x] 优化支付相关订单和记录的查询条件
diff --git a/daxpay-single-demo/pom.xml b/daxpay-single-demo/pom.xml
new file mode 100644
index 000000000..1eadf3b43
--- /dev/null
+++ b/daxpay-single-demo/pom.xml
@@ -0,0 +1,43 @@
+
+
+ 4.0.0
+
+ cn.bootx.platform
+ dax-pay
+ 2.0.0
+
+
+ daxpay-single-demo
+
+
+ 8
+ 8
+ UTF-8
+
+
+
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+
+
+ cn.bootx.platform
+ service-baseapi
+ ${bootx-platform.version}
+
+
+
+
+ cn.bootx.platform
+ daxpay-single-sdk
+ 2.0.0
+
+
+
+
diff --git a/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/DaxPaySingleDemoApp.java b/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/DaxPaySingleDemoApp.java
new file mode 100644
index 000000000..3e9f2711e
--- /dev/null
+++ b/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/DaxPaySingleDemoApp.java
@@ -0,0 +1,12 @@
+package cn.bootx.platform.daxpay.demo;
+
+import org.springframework.context.annotation.ComponentScan;
+
+/**
+ * 支付演示模块
+ * @author xxm
+ * @since 2024/2/8
+ */
+@ComponentScan
+public class DaxPaySingleDemoApp {
+}
diff --git a/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/config/DaxPayDemoProperties.java b/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/config/DaxPayDemoProperties.java
new file mode 100644
index 000000000..6c548420c
--- /dev/null
+++ b/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/config/DaxPayDemoProperties.java
@@ -0,0 +1,28 @@
+package cn.bootx.platform.daxpay.demo.config;
+
+import cn.bootx.platform.daxpay.sdk.code.SignTypeEnum;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * 演示模块配置类
+ * @author xxm
+ * @since 2024/2/8
+ */
+@Getter
+@Setter
+@ConfigurationProperties(prefix = "dax-pay.demo")
+public class DaxPayDemoProperties {
+ /** 服务地址 */
+ private String serverUrl;
+
+ /** 签名方式 */
+ private SignTypeEnum signType = SignTypeEnum.MD5;
+
+ /** 签名秘钥 */
+ private String signSecret;
+
+ /** 请求超时时间 */
+ private int reqTimeout = 30000;
+}
diff --git a/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/config/DaxPayKitConfiguration.java b/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/config/DaxPayKitConfiguration.java
new file mode 100644
index 000000000..5ec45a6a5
--- /dev/null
+++ b/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/config/DaxPayKitConfiguration.java
@@ -0,0 +1,37 @@
+package cn.bootx.platform.daxpay.demo.config;
+
+import cn.bootx.platform.daxpay.sdk.net.DaxPayConfig;
+import cn.bootx.platform.daxpay.sdk.net.DaxPayKit;
+import lombok.RequiredArgsConstructor;
+import org.springframework.boot.context.event.ApplicationStartedEvent;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.event.EventListener;
+
+/**
+ * 初始化
+ * @author xxm
+ * @since 2024/2/8
+ */
+@Configuration
+@RequiredArgsConstructor
+@EnableConfigurationProperties(DaxPayDemoProperties.class)
+public class DaxPayKitConfiguration {
+
+ private final DaxPayDemoProperties daxPayDemoProperties;
+
+ /**
+ * 初始化
+ */
+ @EventListener(ApplicationStartedEvent.class)
+// @EventListener(webstarteve.class)
+ public void initDaxPayKit(){
+ DaxPayConfig config = DaxPayConfig.builder()
+ .serviceUrl(daxPayDemoProperties.getServerUrl())
+ .signType(daxPayDemoProperties.getSignType())
+ .signSecret(daxPayDemoProperties.getSignSecret())
+ .reqTimeout(daxPayDemoProperties.getReqTimeout())
+ .build();
+ DaxPayKit.initConfig(config);
+ }
+}
diff --git a/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/controller/DaxPayCashierController.java b/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/controller/DaxPayCashierController.java
new file mode 100644
index 000000000..ef0d198a3
--- /dev/null
+++ b/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/controller/DaxPayCashierController.java
@@ -0,0 +1,39 @@
+package cn.bootx.platform.daxpay.demo.controller;
+
+import cn.bootx.platform.common.core.rest.Res;
+import cn.bootx.platform.common.core.rest.ResResult;
+import cn.bootx.platform.common.core.util.ValidationUtil;
+import cn.bootx.platform.daxpay.demo.param.CashierSimplePayParam;
+import cn.bootx.platform.daxpay.demo.result.PayOrderResult;
+import cn.bootx.platform.daxpay.demo.service.DaxPayCashierService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 结算台演示
+ * @author xxm
+ * @since 2024/2/8
+ */
+@Tag(name = "结算台演示")
+@RestController
+@RequestMapping("/demo/cashier")
+@RequiredArgsConstructor
+public class DaxPayCashierController {
+
+ private final DaxPayCashierService cashierService;
+
+ @Operation(summary = "创建支付订单并发起")
+ @PostMapping("/simplePayCashier")
+ public ResResult simplePayCashier(@RequestBody CashierSimplePayParam param){
+ ValidationUtil.validateParam(param);
+ return Res.ok(cashierService.simplePayCashier(param));
+ }
+
+ @Operation(summary = "查询支付订单")
+ @GetMapping("/queryPayOrder")
+ public ResResult queryPayOrder(Long paymentId){
+ return Res.ok(cashierService.queryPayOrder(paymentId));
+ }
+}
diff --git a/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/param/CashierSimplePayParam.java b/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/param/CashierSimplePayParam.java
new file mode 100644
index 000000000..a45b4cd11
--- /dev/null
+++ b/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/param/CashierSimplePayParam.java
@@ -0,0 +1,47 @@
+package cn.bootx.platform.daxpay.demo.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
+/**
+ * 结算台简单支付参数(单通道支付)
+ *
+ * @author xxm
+ * @since 2022/2/23
+ */
+@Data
+@Accessors(chain = true)
+@Schema(title = "结算台简单支付参数(单通道支付)")
+public class CashierSimplePayParam {
+
+ @Schema(description = "业务号")
+ @NotNull
+ private String businessNo;
+
+ @Schema(description = "标题")
+ @NotNull
+ private String title;
+
+ @Schema(description = "金额")
+ @NotNull
+ private BigDecimal amount;
+
+ @Schema(description = "openId(微信支付时使用)")
+ private String openId;
+
+ @Schema(description = "支付渠道")
+ @NotNull
+ private String channel;
+
+ @Schema(description = "支付方式")
+ @NotNull
+ private String payWay;
+
+ @Schema(description = "付款码")
+ private String authCode;
+
+}
diff --git a/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/result/PayOrderResult.java b/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/result/PayOrderResult.java
new file mode 100644
index 000000000..0810cba2c
--- /dev/null
+++ b/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/result/PayOrderResult.java
@@ -0,0 +1,31 @@
+package cn.bootx.platform.daxpay.demo.result;
+
+import cn.bootx.platform.daxpay.sdk.code.PayChannelEnum;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 发起支付后响应对象
+ * @author xxm
+ * @since 2024/2/8
+ */
+@Getter
+@Setter
+public class PayOrderResult {
+ /** 支付ID */
+ private Long paymentId;
+
+ /** 是否是异步支付 */
+ private boolean asyncPay;
+
+ /**
+ * 异步支付通道
+ * @see PayChannelEnum
+ */
+ private String asyncChannel;
+
+
+ /** 支付参数体(通常用于发起异步支付的参数) */
+ private String payBody;
+
+}
diff --git a/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/service/DaxPayCashierService.java b/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/service/DaxPayCashierService.java
new file mode 100644
index 000000000..56895ae14
--- /dev/null
+++ b/daxpay-single-demo/src/main/java/cn/bootx/platform/daxpay/demo/service/DaxPayCashierService.java
@@ -0,0 +1,128 @@
+package cn.bootx.platform.daxpay.demo.service;
+
+import cn.bootx.platform.common.core.exception.BizException;
+import cn.bootx.platform.common.spring.util.WebServletUtil;
+import cn.bootx.platform.daxpay.demo.param.CashierSimplePayParam;
+import cn.bootx.platform.daxpay.demo.result.PayOrderResult;
+import cn.bootx.platform.daxpay.sdk.code.PayChannelEnum;
+import cn.bootx.platform.daxpay.sdk.code.PayStatusEnum;
+import cn.bootx.platform.daxpay.sdk.code.PayWayEnum;
+import cn.bootx.platform.daxpay.sdk.model.pay.PayOrderModel;
+import cn.bootx.platform.daxpay.sdk.model.pay.QueryPayOrderModel;
+import cn.bootx.platform.daxpay.sdk.net.DaxPayKit;
+import cn.bootx.platform.daxpay.sdk.param.channel.AliPayParam;
+import cn.bootx.platform.daxpay.sdk.param.channel.WeChatPayParam;
+import cn.bootx.platform.daxpay.sdk.param.pay.QueryPayOrderParam;
+import cn.bootx.platform.daxpay.sdk.param.pay.SimplePayParam;
+import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.extra.servlet.ServletUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * 支付结算台服务类
+ * @author xxm
+ * @since 2024/2/8
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class DaxPayCashierService {
+
+ /**
+ * 结算台简单支付, 创建支付订单并拉起支付
+ */
+ public PayOrderResult simplePayCashier(CashierSimplePayParam param){
+ // 将参数转换为简单支付参数
+ SimplePayParam simplePayParam = new SimplePayParam();
+ simplePayParam.setBusinessNo(param.getBusinessNo());
+ int amount = param.getAmount()
+ .multiply(BigDecimal.valueOf(100))
+ .intValue();
+ simplePayParam.setTitle(param.getTitle());
+ simplePayParam.setAmount(amount);
+ simplePayParam.setChannel(param.getChannel());
+ simplePayParam.setPayWay(param.getPayWay());
+
+ // 支付宝通道
+ if (Objects.equals(PayChannelEnum.ALI.getCode(), param.getChannel())){
+ // 付款码支付
+ if (Objects.equals(PayWayEnum.BARCODE.getCode(), param.getPayWay())){
+ AliPayParam aliPayParam = new AliPayParam();
+ aliPayParam.setAuthCode(param.getAuthCode());
+ simplePayParam.setChannelParam(aliPayParam);
+ }
+ }
+ // 微信通道
+ if (Objects.equals(PayChannelEnum.WECHAT.getCode(), param.getChannel())){
+ WeChatPayParam wechatPayParam = new WeChatPayParam();
+ // 付款码支付
+ if (Objects.equals(PayWayEnum.BARCODE.getCode(), param.getPayWay())){
+ wechatPayParam.setAuthCode(param.getAuthCode());
+ simplePayParam.setChannelParam(wechatPayParam);
+ }
+ // 微信jsapi 方式支付
+ if (Objects.equals(PayWayEnum.JSAPI.getCode(), param.getPayWay())){
+ wechatPayParam.setOpenId(param.getOpenId());
+ simplePayParam.setChannelParam(wechatPayParam);
+ }
+ }
+ String ip = Optional.ofNullable(WebServletUtil.getRequest())
+ .map(ServletUtil::getClientIP)
+ .orElse("127.0.0.1");
+ simplePayParam.setClientIp(ip);
+ // 异步回调地址
+ simplePayParam.setNotifyUrl("http://localhost:9000");
+ // 同步回调地址
+ simplePayParam.setReturnUrl("http://localhost:9000");
+
+ // 发起支付
+ DaxPayResult execute = DaxPayKit.execute(simplePayParam);
+ // 判断是否支付成功
+ if (execute.getCode() != 0){
+ throw new BizException(execute.getMsg());
+ }
+ // 判断是否发起支付成功
+ PayOrderModel payOrderModel = execute.getData();
+
+ // 状态 支付中或支付完成返回
+ List list = Arrays.asList(PayStatusEnum.PROGRESS.getCode(), PayStatusEnum.SUCCESS.getCode());
+ if (list.contains(payOrderModel.getStatus())){
+ PayOrderResult payOrderResult = new PayOrderResult();
+ BeanUtil.copyProperties(payOrderModel, payOrderResult);
+ return payOrderResult;
+ } else {
+ throw new BizException("订单状态异常,无法进行支付");
+ }
+ }
+
+ /**
+ * 订单查询接口
+ */
+ public boolean queryPayOrder(Long paymentId){
+ QueryPayOrderParam queryPayOrderParam = new QueryPayOrderParam();
+ queryPayOrderParam.setPaymentId(paymentId);
+ DaxPayResult execute = DaxPayKit.execute(queryPayOrderParam);
+ if (execute.getCode() != 0){
+ throw new BizException(execute.getMsg());
+ }
+ QueryPayOrderModel data = execute.getData();
+ String status = data.getStatus();
+ if (Objects.equals(status, PayStatusEnum.PROGRESS.getCode())){
+ return false;
+ }
+ else if (Objects.equals(status, PayStatusEnum.SUCCESS.getCode())){
+ return true;
+ } else {
+ throw new BizException("订单状态不是支付中或支付完成,请检查");
+ }
+ }
+}
diff --git a/daxpay-single-demo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/daxpay-single-demo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 000000000..e992c2cf1
--- /dev/null
+++ b/daxpay-single-demo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+cn.bootx.platform.daxpay.demo.DaxPaySingleDemoApp
diff --git a/daxpay-single-sdk/pom.xml b/daxpay-single-sdk/pom.xml
index 702ebd851..e6f2bcde2 100644
--- a/daxpay-single-sdk/pom.xml
+++ b/daxpay-single-sdk/pom.xml
@@ -51,23 +51,34 @@
+
cn.hutool
hutool-all
${hutool.version}
+
ch.qos.logback
logback-classic
${logback-classic.version}
provided
+
org.projectlombok
lombok
${lombok.version}
provided
+
+
+ org.jetbrains
+ annotations
+ 13.0
+ provided
+
+
junit
junit
diff --git a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/model/pay/PayOrderModel.java b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/model/pay/PayOrderModel.java
index 800782b6c..412b4511d 100644
--- a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/model/pay/PayOrderModel.java
+++ b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/model/pay/PayOrderModel.java
@@ -8,7 +8,7 @@ import lombok.Setter;
import lombok.ToString;
/**
- * 支付相应对象
+ * 发起支付后响应对象
* @author xxm
* @since 2024/2/2
*/
diff --git a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/net/DaxPayKit.java b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/net/DaxPayKit.java
index b8b38483f..36f7adcf6 100644
--- a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/net/DaxPayKit.java
+++ b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/net/DaxPayKit.java
@@ -8,6 +8,7 @@ import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import lombok.experimental.UtilityClass;
+import lombok.extern.slf4j.Slf4j;
import java.util.Objects;
@@ -16,12 +17,14 @@ import java.util.Objects;
* @author xxm
* @since 2024/2/2
*/
+@Slf4j
@UtilityClass
public class DaxPayKit {
private DaxPayConfig config;
public void initConfig(DaxPayConfig config){
+ log.debug("DaxPayKit初始化...");
DaxPayKit.config = config;
}
@@ -54,12 +57,14 @@ public class DaxPayKit {
}
}
String data = JSONUtil.toJsonStr(request);
+ log.debug("请求参数:{}", data);
String path = config.getServiceUrl() + request.path();
HttpResponse execute = HttpUtil.createPost(path)
.body(data, ContentType.JSON.getValue())
.timeout(config.getReqTimeout())
.execute();
String body = execute.body();
+ log.debug("响应参数:{}", body);
return request.toModel(body);
}
}
diff --git a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/ChannelParam.java b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/ChannelParam.java
index 461e6862c..80bca877b 100644
--- a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/ChannelParam.java
+++ b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/ChannelParam.java
@@ -5,5 +5,5 @@ package cn.bootx.platform.daxpay.sdk.param;
* @author xxm
* @since 2023/12/17
*/
-public interface ChannelParam {
+public interface ChannelParam extends SortMapParam {
}
diff --git a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/SortMapParam.java b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/SortMapParam.java
new file mode 100644
index 000000000..8ddd5d3ce
--- /dev/null
+++ b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/SortMapParam.java
@@ -0,0 +1,9 @@
+package cn.bootx.platform.daxpay.sdk.param;
+
+/**
+ * 标示字段可以转换为MAP进行排序
+ * @author xxm
+ * @since 2024/2/8
+ */
+public interface SortMapParam {
+}
diff --git a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/pay/QueryPayParam.java b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/pay/QueryPayOrderParam.java
similarity index 92%
rename from daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/pay/QueryPayParam.java
rename to daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/pay/QueryPayOrderParam.java
index e830ca982..89f0e67af 100644
--- a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/pay/QueryPayParam.java
+++ b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/pay/QueryPayOrderParam.java
@@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
*/
@EqualsAndHashCode(callSuper = true)
@Data
-public class QueryPayParam extends DaxPayRequest {
+public class QueryPayOrderParam extends DaxPayRequest {
/** 支付ID */
private Long paymentId;
diff --git a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/pay/SimplePayParam.java b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/pay/SimplePayParam.java
index 9c357185d..7057bbf80 100644
--- a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/pay/SimplePayParam.java
+++ b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/pay/SimplePayParam.java
@@ -15,6 +15,7 @@ import cn.hutool.json.JSONUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
+import org.jetbrains.annotations.NotNull;
/**
* 简单支付请求参数
@@ -27,9 +28,11 @@ import lombok.ToString;
public class SimplePayParam extends DaxPayRequest {
/** 业务号 */
+ @NotNull
private String businessNo;
/** 支付标题 */
+ @NotNull
private String title;
/** 支付描述 */
@@ -42,17 +45,21 @@ public class SimplePayParam extends DaxPayRequest {
private String quitUrl;
/**
+ * 支付通道
* @see PayChannelEnum#getCode()
*/
+ @NotNull
private String channel;
/**
* 支付方式编码
* @see PayWayEnum#getCode()
*/
+ @NotNull
private String payWay;
/** 支付金额 */
+ @NotNull
private Integer amount;
/**
diff --git a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/refund/QueryRefundParam.java b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/refund/QueryRefundOrderParam.java
similarity index 92%
rename from daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/refund/QueryRefundParam.java
rename to daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/refund/QueryRefundOrderParam.java
index 15c3c38e7..f714659ce 100644
--- a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/refund/QueryRefundParam.java
+++ b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/param/refund/QueryRefundOrderParam.java
@@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode;
*/
@EqualsAndHashCode(callSuper = true)
@Data
-public class QueryRefundParam extends DaxPayRequest {
+public class QueryRefundOrderParam extends DaxPayRequest {
/** 退款ID */
private Long refundId;
diff --git a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/util/PaySignUtil.java b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/util/PaySignUtil.java
index a86764b3f..8415ae451 100644
--- a/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/util/PaySignUtil.java
+++ b/daxpay-single-sdk/src/main/java/cn/bootx/platform/daxpay/sdk/util/PaySignUtil.java
@@ -2,6 +2,7 @@ package cn.bootx.platform.daxpay.sdk.util;
import cn.bootx.platform.daxpay.sdk.param.SortMapParam;
import cn.hutool.core.util.ClassUtil;
+import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.HmacAlgorithm;
import cn.hutool.json.JSONUtil;
@@ -94,9 +95,8 @@ public class PaySignUtil {
}
}
-
/**
- * 把所有元素排序, 并拼接成字符, 用于签名
+ * 把所有元素排序, 并拼接成字符, 用于签名, 同时会过滤掉 " 和 \ 字符
*/
public static String createLinkString(Map params) {
String connStr = "&";
@@ -118,10 +118,12 @@ public class PaySignUtil {
.append(connStr);
}
}
- return content.toString();
+ String s = content.toString();
+ s = StrUtil.replace(s,"\\","");
+ s = StrUtil.replace(s,"\"","");
+ return s;
}
-
/**
* 生成16进制 MD5 字符串
*
diff --git a/daxpay-single-sdk/src/test/java/cn/bootx/platform/daxpay/sdk/query/QueryPayOrderTest.java b/daxpay-single-sdk/src/test/java/cn/bootx/platform/daxpay/sdk/query/QueryPayOrderTest.java
index 5152271c8..9758efd9b 100644
--- a/daxpay-single-sdk/src/test/java/cn/bootx/platform/daxpay/sdk/query/QueryPayOrderTest.java
+++ b/daxpay-single-sdk/src/test/java/cn/bootx/platform/daxpay/sdk/query/QueryPayOrderTest.java
@@ -3,7 +3,7 @@ package cn.bootx.platform.daxpay.sdk.query;
import cn.bootx.platform.daxpay.sdk.model.pay.QueryPayOrderModel;
import cn.bootx.platform.daxpay.sdk.net.DaxPayConfig;
import cn.bootx.platform.daxpay.sdk.net.DaxPayKit;
-import cn.bootx.platform.daxpay.sdk.param.pay.QueryPayParam;
+import cn.bootx.platform.daxpay.sdk.param.pay.QueryPayOrderParam;
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
import org.junit.Before;
import org.junit.Test;
@@ -27,7 +27,7 @@ public class QueryPayOrderTest {
@Test
public void testPay() {
- QueryPayParam param = new QueryPayParam();
+ QueryPayOrderParam param = new QueryPayOrderParam();
param.setBusinessNo("2");
diff --git a/daxpay-single-sdk/src/test/java/cn/bootx/platform/daxpay/sdk/query/QueryRefundOrderTest.java b/daxpay-single-sdk/src/test/java/cn/bootx/platform/daxpay/sdk/query/QueryRefundOrderTest.java
index 54c5e4305..86fbff96d 100644
--- a/daxpay-single-sdk/src/test/java/cn/bootx/platform/daxpay/sdk/query/QueryRefundOrderTest.java
+++ b/daxpay-single-sdk/src/test/java/cn/bootx/platform/daxpay/sdk/query/QueryRefundOrderTest.java
@@ -3,7 +3,7 @@ package cn.bootx.platform.daxpay.sdk.query;
import cn.bootx.platform.daxpay.sdk.model.refund.QueryRefundOrderModel;
import cn.bootx.platform.daxpay.sdk.net.DaxPayConfig;
import cn.bootx.platform.daxpay.sdk.net.DaxPayKit;
-import cn.bootx.platform.daxpay.sdk.param.refund.QueryRefundParam;
+import cn.bootx.platform.daxpay.sdk.param.refund.QueryRefundOrderParam;
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
import org.junit.Before;
import org.junit.Test;
@@ -27,7 +27,7 @@ public class QueryRefundOrderTest {
@Test
public void testPay() {
- QueryRefundParam param = new QueryRefundParam();
+ QueryRefundOrderParam param = new QueryRefundOrderParam();
param.setRefundId(1755263825769361408L);
diff --git a/daxpay-single-sdk/src/test/java/cn/bootx/platform/daxpay/sdk/util/PayParamSignTest.java b/daxpay-single-sdk/src/test/java/cn/bootx/platform/daxpay/sdk/util/PayParamSignTest.java
index 04e8c130e..a3016fc83 100644
--- a/daxpay-single-sdk/src/test/java/cn/bootx/platform/daxpay/sdk/util/PayParamSignTest.java
+++ b/daxpay-single-sdk/src/test/java/cn/bootx/platform/daxpay/sdk/util/PayParamSignTest.java
@@ -2,6 +2,7 @@ package cn.bootx.platform.daxpay.sdk.util;
import cn.bootx.platform.daxpay.sdk.code.PayChannelEnum;
import cn.bootx.platform.daxpay.sdk.code.PayWayEnum;
+import cn.bootx.platform.daxpay.sdk.param.channel.WeChatPayParam;
import cn.bootx.platform.daxpay.sdk.param.pay.PayChannelParam;
import cn.bootx.platform.daxpay.sdk.param.pay.PayParam;
import lombok.extern.slf4j.Slf4j;
@@ -43,7 +44,42 @@ public class PayParamSignTest {
Map map = PaySignUtil.toMap(param);
log.info("转换为有序MAP后的内容: {}",map);
String data = PaySignUtil.createLinkString(map);
- log.info("将MAP拼接字符串: {}",data);
+ log.info("将MAP拼接字符串, 并过滤掉特殊字符: {}",data);
+ String sign = "123456";
+ data += "&sign="+sign;
+ data = data.toUpperCase();
+ log.info("添加秘钥并转换为大写的字符串: {}",data);
+ log.info("MD5: {}",PaySignUtil.md5(data));
+ log.info("HmacSHA256: {}",PaySignUtil.hmacSha256(data,sign));
+ }
+
+ /**
+ * 多层嵌套对象签名测试
+ */
+ @Test
+ public void sign2(){
+
+ PayParam param = new PayParam();
+ param.setClientIp("127.0.0.1");
+
+ param.setBusinessNo("P0002");
+ param.setTitle("测试接口支付");
+ PayChannelParam payChannelParam = new PayChannelParam();
+ payChannelParam.setChannel(PayChannelEnum.WECHAT.getCode());
+ payChannelParam.setWay(PayWayEnum.QRCODE.getCode());
+ payChannelParam.setAmount(1);
+ WeChatPayParam weChatPayParam = new WeChatPayParam();
+ weChatPayParam.setOpenId("6688812");
+ weChatPayParam.setAuthCode("123456");
+ payChannelParam.setChannelParam(weChatPayParam);
+
+ List payChannels = Collections.singletonList(payChannelParam);
+ param.setPayChannels(payChannels);
+
+ Map map = PaySignUtil.toMap(param);
+ log.info("转换为有序MAP后的内容: {}",map);
+ String data = PaySignUtil.createLinkString(map).replaceAll("\\\"","").replaceAll("\"","");
+ log.info("将MAP拼接字符串, 并过滤掉特殊字符: {}",data);
String sign = "123456";
data += "&sign="+sign;
data = data.toUpperCase();
diff --git a/daxpay-single/daxpay-single-admin/pom.xml b/daxpay-single/daxpay-single-admin/pom.xml
index 02d5a3a57..dcf62f05e 100644
--- a/daxpay-single/daxpay-single-admin/pom.xml
+++ b/daxpay-single/daxpay-single-admin/pom.xml
@@ -16,8 +16,9 @@
cn.bootx.platform
daxpay-single-service
- ${dax.version}
+ ${daxpay.version}
+
cn.bootx.platform
diff --git a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/PayChannelParam.java b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/PayChannelParam.java
index 088117f2b..813068cb1 100644
--- a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/PayChannelParam.java
+++ b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/PayChannelParam.java
@@ -11,6 +11,7 @@ import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
+import java.util.Map;
/**
* 同意下单支付方式参数
@@ -48,5 +49,5 @@ public class PayChannelParam {
* @see WalletPayParam
*/
@Schema(description = "附加支付参数")
- private String channelParam;
+ private Map channelParam;
}
diff --git a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/SimplePayParam.java b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/SimplePayParam.java
index ea7f6dc47..92577e6c4 100644
--- a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/SimplePayParam.java
+++ b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/SimplePayParam.java
@@ -16,6 +16,7 @@ import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
+import java.util.Map;
/**
* 简单下单参数
@@ -71,7 +72,7 @@ public class SimplePayParam extends PayCommonParam{
* @see WalletPayParam
*/
@Schema(description = "附加通道支付参数")
- private String channelParam;
+ private Map channelParam;
}
diff --git a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/util/PaySignUtil.java b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/util/PaySignUtil.java
index 48012f478..fe4d703ff 100644
--- a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/util/PaySignUtil.java
+++ b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/util/PaySignUtil.java
@@ -2,6 +2,7 @@ package cn.bootx.platform.daxpay.util;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.hutool.core.util.ClassUtil;
+import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.HmacAlgorithm;
import cn.hutool.json.JSONUtil;
@@ -99,7 +100,7 @@ public class PaySignUtil {
/**
- * 把所有元素排序, 并拼接成字符, 用于签名
+ * 把所有元素排序, 并拼接成字符, 用于签名, 同时会过滤掉 " 和 \ 字符
*/
public static String createLinkString(Map params) {
String connStr = "&";
@@ -121,7 +122,10 @@ public class PaySignUtil {
.append(connStr);
}
}
- return content.toString();
+ String s = content.toString();
+ s = StrUtil.replace(s,"\\","");
+ s = StrUtil.replace(s,"\"","");
+ return s;
}
diff --git a/daxpay-single/daxpay-single-gateway/pom.xml b/daxpay-single/daxpay-single-gateway/pom.xml
index 130cdce50..10bef0624 100644
--- a/daxpay-single/daxpay-single-gateway/pom.xml
+++ b/daxpay-single/daxpay-single-gateway/pom.xml
@@ -15,7 +15,7 @@
cn.bootx.platform
daxpay-single-service
- ${dax.version}
+ ${daxpay.version}
diff --git a/daxpay-single/daxpay-single-service/pom.xml b/daxpay-single/daxpay-single-service/pom.xml
index 4cf0b71f6..2941968b0 100644
--- a/daxpay-single/daxpay-single-service/pom.xml
+++ b/daxpay-single/daxpay-single-service/pom.xml
@@ -70,7 +70,7 @@
cn.bootx.platform
daxpay-single-core
- ${dax.version}
+ ${daxpay.version}
@@ -109,6 +109,7 @@
junit-jupiter
test
+
com.baomidou
lock4j-redis-template-spring-boot-starter
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/voucher/service/VoucherPayService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/voucher/service/VoucherPayService.java
index cd042905f..3b8849301 100644
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/voucher/service/VoucherPayService.java
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/voucher/service/VoucherPayService.java
@@ -1,5 +1,8 @@
package cn.bootx.platform.daxpay.service.core.channel.voucher.service;
+import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
+import cn.bootx.platform.daxpay.param.channel.VoucherPayParam;
+import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
import cn.bootx.platform.daxpay.service.code.VoucherCode;
import cn.bootx.platform.daxpay.service.core.channel.voucher.dao.VoucherLogManager;
import cn.bootx.platform.daxpay.service.core.channel.voucher.dao.VoucherManager;
@@ -9,17 +12,17 @@ import cn.bootx.platform.daxpay.service.core.channel.voucher.entity.VoucherLog;
import cn.bootx.platform.daxpay.service.core.channel.voucher.entity.VoucherPayOrder;
import cn.bootx.platform.daxpay.service.core.channel.voucher.entity.VoucherRecord;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
-import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
-import cn.bootx.platform.daxpay.param.channel.VoucherPayParam;
-import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONException;
-import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import java.util.Map;
+
/**
* 储值卡支付
*
@@ -46,9 +49,10 @@ public class VoucherPayService {
VoucherPayParam voucherPayParam;
try {
// 储值卡参数验证
- String extraParamsJson = payChannelParam.getChannelParam();
- if (StrUtil.isNotBlank(extraParamsJson)) {
- voucherPayParam = JSONUtil.toBean(extraParamsJson, VoucherPayParam.class);
+
+ Map channelParam = payChannelParam.getChannelParam();
+ if (CollUtil.isNotEmpty(channelParam)) {
+ voucherPayParam = BeanUtil.toBean(channelParam, VoucherPayParam.class);
} else {
throw new PayFailureException("储值卡支付参数错误");
}
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/pay/builder/PayBuilder.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/pay/builder/PayBuilder.java
index 610499f79..98ab5a8a8 100644
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/pay/builder/PayBuilder.java
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/pay/builder/PayBuilder.java
@@ -2,6 +2,9 @@ package cn.bootx.platform.daxpay.service.core.order.pay.builder;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.code.PayStatusEnum;
+import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
+import cn.bootx.platform.daxpay.param.pay.PayParam;
+import cn.bootx.platform.daxpay.result.pay.PayResult;
import cn.bootx.platform.daxpay.service.common.context.AsyncPayLocal;
import cn.bootx.platform.daxpay.service.common.context.NoticeLocal;
import cn.bootx.platform.daxpay.service.common.context.PlatformLocal;
@@ -9,20 +12,15 @@ import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrderExtra;
-import cn.bootx.platform.daxpay.entity.RefundableInfo;
-import cn.bootx.platform.daxpay.param.pay.PayParam;
-import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
-import cn.bootx.platform.daxpay.result.pay.PayResult;
-import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
import lombok.experimental.UtilityClass;
import java.time.LocalDateTime;
-import java.util.Collections;
-import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Optional;
-import java.util.stream.Collectors;
/**
* 支付对象构建器
@@ -91,28 +89,19 @@ public class PayBuilder {
* 构建订单关联通道信息
*/
public PayChannelOrder buildPayChannelOrder(PayChannelParam channelParam) {
- return new PayChannelOrder()
+ PayChannelOrder payChannelOrder = new PayChannelOrder()
.setAsync(PayChannelEnum.ASYNC_TYPE_CODE.contains(channelParam.getChannel()))
.setChannel(channelParam.getChannel())
.setPayWay(channelParam.getWay())
.setAmount(channelParam.getAmount())
- .setRefundableBalance(channelParam.getAmount())
- .setChannelExtra(channelParam.getChannelParam());
- }
+ .setRefundableBalance(channelParam.getAmount());
- /**
- * 构建支付订单的可退款信息列表
- */
- @Deprecated
- private List buildRefundableInfo(List payChannelParamList) {
- if (CollectionUtil.isEmpty(payChannelParamList)) {
- return Collections.emptyList();
+ Map cp = channelParam.getChannelParam();
+ if (CollUtil.isNotEmpty(cp)){
+ payChannelOrder.setChannelExtra(JSONUtil.toJsonStr(cp));
}
- return payChannelParamList.stream()
- .map(o-> new RefundableInfo()
- .setChannel(o.getChannel())
- .setAmount(o.getAmount()))
- .collect(Collectors.toList());
+
+ return payChannelOrder;
}
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/pay/entity/PayChannelOrder.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/pay/entity/PayChannelOrder.java
index af36a76ee..176c8cdee 100644
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/pay/entity/PayChannelOrder.java
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/pay/entity/PayChannelOrder.java
@@ -11,6 +11,8 @@ import cn.bootx.platform.daxpay.service.core.order.pay.convert.PayOrderConvert;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayChannelOrderDto;
import cn.bootx.table.modify.annotation.DbColumn;
import cn.bootx.table.modify.annotation.DbTable;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -66,6 +68,7 @@ public class PayChannelOrder extends MpCreateEntity implements EntityBaseFunctio
* @see WalletPayParam
*/
@DbColumn(comment = "附加支付参数")
+ @TableField(updateStrategy = FieldStrategy.NEVER)
private String channelExtra;
/**
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/pay/service/PayChannelOrderService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/pay/service/PayChannelOrderService.java
index c0bde41a7..1b852cd6b 100644
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/pay/service/PayChannelOrderService.java
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/order/pay/service/PayChannelOrderService.java
@@ -12,6 +12,7 @@ import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder;
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
import cn.bootx.platform.daxpay.service.core.order.refund.entity.PayRefundChannelOrder;
import cn.bootx.platform.daxpay.service.dto.order.pay.PayChannelOrderDto;
+import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -19,6 +20,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -57,6 +59,12 @@ public class PayChannelOrderService {
PayStatusEnum payStatus = asyncPayInfo.isPayComplete() ? PayStatusEnum.SUCCESS : PayStatusEnum.PROGRESS;
// 判断新发起的
Optional payOrderChannelOpt = channelOrderManager.findByPaymentIdAndChannel(payOrder.getId(), payChannelParam.getChannel());
+ // 扩展信息处理
+ Map channelParam = payChannelParam.getChannelParam();
+ String channelParamStr = null;
+ if (Objects.nonNull(channelParam)){
+ channelParamStr = JSONUtil.toJsonStr(channelParam);
+ }
if (!payOrderChannelOpt.isPresent()){
PayChannelOrder payChannelOrder = new PayChannelOrder();
// 替换原有的的支付通道信息
@@ -68,7 +76,7 @@ public class PayChannelOrderService {
.setAmount(payChannelParam.getAmount())
.setRefundableBalance(payChannelParam.getAmount())
.setPayTime(LocalDateTime.now())
- .setChannelExtra(payChannelParam.getChannelParam())
+ .setChannelExtra(channelParamStr)
.setStatus(payStatus.getCode());
channelOrderManager.deleteByPaymentIdAndAsync(payOrder.getId());
channelOrderManager.save(payChannelOrder);
@@ -77,7 +85,7 @@ public class PayChannelOrderService {
payOrderChannelOpt.get()
.setPayWay(payChannelParam.getWay())
.setPayTime(LocalDateTime.now())
- .setChannelExtra(payChannelParam.getChannelParam())
+ .setChannelExtra(channelParamStr)
.setStatus(payStatus.getCode());
channelOrderManager.updateById(payOrderChannelOpt.get());
}
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/AliPayStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/AliPayStrategy.java
index 4eca935f3..365b71dee 100644
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/AliPayStrategy.java
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/AliPayStrategy.java
@@ -10,13 +10,15 @@ import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayConfig
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayService;
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayChannelOrderService;
import cn.bootx.platform.daxpay.service.func.AbsPayStrategy;
-import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONException;
-import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
+import java.util.Map;
+
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
/**
@@ -52,9 +54,9 @@ public class AliPayStrategy extends AbsPayStrategy {
public void doBeforePayHandler() {
try {
// 支付宝参数验证
- String extraParamsJson = this.getPayChannelParam().getChannelParam();
- if (StrUtil.isNotBlank(extraParamsJson)) {
- this.aliPayParam = JSONUtil.toBean(extraParamsJson, AliPayParam.class);
+ Map channelParam = this.getPayChannelParam().getChannelParam();
+ if (CollUtil.isNotEmpty(channelParam)) {
+ this.aliPayParam = BeanUtil.toBean(channelParam, AliPayParam.class);
}
else {
this.aliPayParam = new AliPayParam();
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WalletPayStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WalletPayStrategy.java
index a5b2a3712..973afa6b7 100644
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WalletPayStrategy.java
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WalletPayStrategy.java
@@ -1,23 +1,24 @@
package cn.bootx.platform.daxpay.service.core.payment.pay.strategy;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
-import cn.bootx.platform.daxpay.service.code.WalletCode;
-import cn.bootx.platform.daxpay.service.core.channel.wallet.entity.Wallet;
-import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletPayService;
-import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletPayOrderService;
-import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletQueryService;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.exception.waller.WalletBannedException;
import cn.bootx.platform.daxpay.exception.waller.WalletLackOfBalanceException;
+import cn.bootx.platform.daxpay.service.code.WalletCode;
+import cn.bootx.platform.daxpay.service.core.channel.wallet.entity.Wallet;
+import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletPayOrderService;
+import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletPayService;
+import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletQueryService;
import cn.bootx.platform.daxpay.service.func.AbsPayStrategy;
import cn.bootx.platform.daxpay.service.param.channel.wallet.WalletPayParam;
-import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONException;
-import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
+import java.util.Map;
import java.util.Objects;
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
@@ -54,9 +55,9 @@ public class WalletPayStrategy extends AbsPayStrategy {
WalletPayParam walletPayParam = new WalletPayParam();
try {
// 钱包参数验证
- String extraParamsJson = this.getPayChannelParam().getChannelParam();
- if (StrUtil.isNotBlank(extraParamsJson)) {
- walletPayParam = JSONUtil.toBean(extraParamsJson, WalletPayParam.class);
+ Map channelParam = this.getPayChannelParam().getChannelParam();
+ if (CollUtil.isNotEmpty(channelParam)) {
+ walletPayParam = BeanUtil.toBean(channelParam, WalletPayParam.class);
}
} catch (JSONException e) {
throw new PayFailureException("支付参数错误");
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WeChatPayStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WeChatPayStrategy.java
index 8796d181a..2581cb9d9 100644
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WeChatPayStrategy.java
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WeChatPayStrategy.java
@@ -2,7 +2,6 @@ package cn.bootx.platform.daxpay.service.core.payment.pay.strategy;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
import cn.bootx.platform.daxpay.exception.pay.PayAmountAbnormalException;
-import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayConfigService;
@@ -10,13 +9,14 @@ import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPaySer
import cn.bootx.platform.daxpay.service.core.order.pay.service.PayChannelOrderService;
import cn.bootx.platform.daxpay.service.func.AbsPayStrategy;
import cn.bootx.platform.daxpay.service.param.channel.wechat.WeChatPayParam;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.json.JSONException;
-import cn.hutool.json.JSONUtil;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
+import java.util.Map;
+
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
/**
@@ -53,18 +53,12 @@ public class WeChatPayStrategy extends AbsPayStrategy {
*/
@Override
public void doBeforePayHandler() {
- try {
- // 微信参数验证
- String extraParamsJson = this.getPayChannelParam().getChannelParam();
- if (StrUtil.isNotBlank(extraParamsJson)) {
- this.weChatPayParam = JSONUtil.toBean(extraParamsJson, WeChatPayParam.class);
- }
- else {
- this.weChatPayParam = new WeChatPayParam();
- }
- }
- catch (JSONException e) {
- throw new PayFailureException("支付参数错误");
+ // 微信参数验证
+ Map channelParam = this.getPayChannelParam().getChannelParam();
+ if (CollUtil.isNotEmpty(channelParam)) {
+ this.weChatPayParam = BeanUtil.toBean(channelParam, WeChatPayParam.class);
+ } else {
+ this.weChatPayParam = new WeChatPayParam();
}
// 检查金额
diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/timeout/task/PayExpiredTimeTask.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/timeout/task/PayExpiredTimeTask.java
index 26b6489d2..d58086530 100644
--- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/timeout/task/PayExpiredTimeTask.java
+++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/timeout/task/PayExpiredTimeTask.java
@@ -54,6 +54,10 @@ public class PayExpiredTimeTask {
paySyncParam.setPaymentId(paymentId);
paySyncService.sync(paySyncParam);
} catch (Exception e) {
+ // 如果是未查询到取消支付订单, 则删除这个任务
+ if (Objects.equals("未查询到支付订单", e.getMessage())){
+ repository.removeKeys(expiredKey);
+ }
log.error("超时取消任务 异常", e);
} finally {
lockTemplate.releaseLock(lock);
diff --git a/daxpay-single/daxpay-single-service/src/test/java/cn/bootx/platform/daxpay/core/payment/common/service/PaymentSignServiceTest.java b/daxpay-single/daxpay-single-service/src/test/java/cn/bootx/platform/daxpay/core/util/PayParamSignTest.java
similarity index 68%
rename from daxpay-single/daxpay-single-service/src/test/java/cn/bootx/platform/daxpay/core/payment/common/service/PaymentSignServiceTest.java
rename to daxpay-single/daxpay-single-service/src/test/java/cn/bootx/platform/daxpay/core/util/PayParamSignTest.java
index 89da03e41..62bf97788 100644
--- a/daxpay-single/daxpay-single-service/src/test/java/cn/bootx/platform/daxpay/core/payment/common/service/PaymentSignServiceTest.java
+++ b/daxpay-single/daxpay-single-service/src/test/java/cn/bootx/platform/daxpay/core/util/PayParamSignTest.java
@@ -1,17 +1,18 @@
-package cn.bootx.platform.daxpay.core.payment.common.service;
+package cn.bootx.platform.daxpay.core.util;
import cn.bootx.platform.daxpay.param.channel.AliPayParam;
import cn.bootx.platform.daxpay.param.channel.WeChatPayParam;
import cn.bootx.platform.daxpay.param.pay.PayChannelParam;
import cn.bootx.platform.daxpay.param.pay.PayParam;
import cn.bootx.platform.daxpay.util.PaySignUtil;
-import cn.hutool.json.JSONUtil;
+import cn.hutool.core.bean.BeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
/**
* 支付签名服务
@@ -19,7 +20,7 @@ import java.util.List;
* @since 2023/12/24
*/
@Slf4j
-class PaymentSignServiceTest {
+class PayParamSignTest {
@Test
void toMap() {
@@ -40,7 +41,7 @@ class PaymentSignServiceTest {
p1.setWay("wx_app");
AliPayParam aliPayParam = new AliPayParam();
aliPayParam.setAuthCode("6688");
- p1.setChannelParam(JSONUtil.toJsonStr(aliPayParam));
+ p1.setChannelParam(BeanUtil.beanToMap(aliPayParam,false,true));
PayChannelParam p2 = new PayChannelParam();
p2.setAmount(100);
@@ -49,17 +50,21 @@ class PaymentSignServiceTest {
WeChatPayParam weChatPayParam = new WeChatPayParam();
weChatPayParam.setOpenId("w2qsz2xawe3gbhyyff28fs01fd");
weChatPayParam.setAuthCode("8866");
- p2.setChannelParam(JSONUtil.toJsonStr(weChatPayParam));
+ p2.setChannelParam(BeanUtil.beanToMap(aliPayParam,false,true));
List payWays = Arrays.asList(p1, p2);
payParam.setPayChannels(payWays);
- // 签名
- String sign = "123456";
- String md5Sign = PaySignUtil.md5Sign(payParam, sign);
- String hmacSha256Sign = PaySignUtil.hmacSha256Sign(payParam, sign);
- log.info("MD5: {}",md5Sign);
- log.info("HmacSHA256: {}", hmacSha256Sign);
+ Map map = PaySignUtil.toMap(payParam);
+ log.info("转换为有序MAP后的内容: {}",map);
+ String data = PaySignUtil.createLinkString(map);
+ log.info("将MAP拼接字符串, 并过滤掉特殊字符: {}",data);
+ String sign = "123456";
+ data += "&sign="+sign;
+ data = data.toUpperCase();
+ log.info("添加秘钥并转换为大写的字符串: {}",data);
+ log.info("MD5: {}",PaySignUtil.md5(data));
+ log.info("HmacSHA256: {}",PaySignUtil.hmacSha256(data,sign));
}
}
diff --git a/daxpay-single/daxpay-single-start/pom.xml b/daxpay-single/daxpay-single-start/pom.xml
index 44ab94d0e..c48e97ef9 100644
--- a/daxpay-single/daxpay-single-start/pom.xml
+++ b/daxpay-single/daxpay-single-start/pom.xml
@@ -16,13 +16,13 @@
cn.bootx.platform
daxpay-single-gateway
- ${dax.version}
+ ${daxpay.version}
cn.bootx.platform
daxpay-single-admin
- ${dax.version}
+ ${daxpay.version}
@@ -35,7 +35,11 @@
common-starter-code-gen
-
+
+ cn.bootx.platform
+ daxpay-single-demo
+ ${daxpay.version}
+
diff --git a/daxpay-single/daxpay-single-start/src/main/resources/application-dev.yml b/daxpay-single/daxpay-single-start/src/main/resources/application-dev.yml
index 3d15b6d62..999300b06 100644
--- a/daxpay-single/daxpay-single-start/src/main/resources/application-dev.yml
+++ b/daxpay-single/daxpay-single-start/src/main/resources/application-dev.yml
@@ -72,6 +72,7 @@ bootx:
base-packages:
"[支付网关API]": cn.bootx.platform.daxpay.gateway
"[支付管理接口]": cn.bootx.platform.daxpay.admin
+ "[支付演示模块]": cn.bootx.platform.daxpay.demo
"[BootxPlatform接口]":
- cn.bootx.platform.common
- cn.bootx.platform.starter
@@ -150,3 +151,11 @@ dromara:
enableStorage: true
# 文件存储路径
storage-path: D:/data/files/
+# 支付系统配置
+dax-pay:
+ # 演示模块
+ demo:
+ # 网关地址
+ server-url: http://localhost:9000
+ # 签名秘钥
+ sign-secret: 123456
diff --git a/pom.xml b/pom.xml
index 02a0341f0..1868f4d23 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,6 +20,7 @@
daxpay-single
daxpay-single-sdk
+ daxpay-single-demo
@@ -29,7 +30,7 @@
1.3.6.1
- 2.0.0
+ 2.0.0
1.7.30
3.16.8