mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-04 03:30:36 +00:00
feat SDK编写
This commit is contained in:
@@ -99,10 +99,11 @@
|
||||
- [x] 支付和退款同步时, 填充完成时间和网关订单号
|
||||
- 2024-02-01:
|
||||
- [x] 支付切换异步方式时, 订单未更换
|
||||
- [ ] 支付同步时, 支付宝未支付订单无法自动关闭
|
||||
- [ ] 调整订单页面查询条件
|
||||
-
|
||||
|
||||
- [x] 支付同步时, 支付宝未支付订单无法自动关闭
|
||||
- [x] 调整订单页面查询条件
|
||||
- 2024-02-02:
|
||||
- [ ] 接入SDK编写
|
||||
- [ ] 接入支付网关的演示项目
|
||||
- 2.0.1 版本内容
|
||||
- [ ] 退款操作支持重试
|
||||
- [ ] 支付流程也改为先落库后支付情况, 避免极端情况导致掉单
|
||||
|
@@ -4,7 +4,7 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>cn.bootx.cloud</groupId>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>daxpay-single-sdk</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
@@ -13,13 +13,34 @@
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<logback-classic.version>1.2.7</logback-classic.version>
|
||||
<hutool.version>5.8.25</hutool.version>
|
||||
<lombok.version>1.18.30</lombok.version>
|
||||
<junit.version>4.13.2</junit.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.24</version>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback-classic.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
@@ -0,0 +1,41 @@
|
||||
package cn.bootx.platform.daxpay.sdk.code;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 支付通道枚举
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2021/7/26
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum PayChannelEnum {
|
||||
|
||||
ALI("ali_pay", "支付宝"),
|
||||
WECHAT("wechat_pay", "微信支付"),
|
||||
UNION_PAY("union_pay", "云闪付"),
|
||||
CASH("cash_pay", "现金支付"),
|
||||
WALLET("wallet_pay", "钱包支付"),
|
||||
VOUCHER("voucher_pay", "储值卡支付");
|
||||
/** 支付通道编码 */
|
||||
private final String code;
|
||||
/** 支付通道名称 */
|
||||
private final String name;
|
||||
|
||||
|
||||
/**
|
||||
* 根据编码获取枚举
|
||||
*/
|
||||
public static PayChannelEnum findByCode(String code){
|
||||
return Arrays.stream(values())
|
||||
.filter(o -> Objects.equals(o.getCode(), code))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("该枚举不存在"));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
package cn.bootx.platform.daxpay.sdk.code;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 支付状态
|
||||
* @author xxm
|
||||
* @since 2023/12/17
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum PayStatusEnum {
|
||||
PROGRESS("progress","支付中"),
|
||||
SUCCESS("success","成功"),
|
||||
CLOSE("close","支付关闭"),
|
||||
REFUNDING("refunding","退款中"),
|
||||
PARTIAL_REFUND("partial_refund","部分退款"),
|
||||
REFUNDED("refunded","全部退款"),
|
||||
FAIL("fail","失败");
|
||||
|
||||
/** 编码 */
|
||||
private final String code;
|
||||
|
||||
/** 名称 */
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* 根据编码获取枚举
|
||||
*/
|
||||
public static PayStatusEnum findByCode(String code){
|
||||
return Arrays.stream(values())
|
||||
.filter(o -> Objects.equals(o.getCode(), code))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("该枚举不存在"));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
package cn.bootx.platform.daxpay.sdk.code;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 支付方式
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2021/7/26
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum PayWayEnum {
|
||||
|
||||
NORMAL("normal", "常规支付"),
|
||||
WAP("wap", "wap支付"),
|
||||
APP("app", "应用支付"),
|
||||
WEB("web", "web支付"),
|
||||
QRCODE("qrcode", "扫码支付"),
|
||||
BARCODE("barcode", "付款码"),
|
||||
JSAPI("jsapi", "公众号/小程序支付");
|
||||
|
||||
/** 编码 */
|
||||
private final String code;
|
||||
/** 名称 */
|
||||
private final String name;
|
||||
/**
|
||||
* 根据编码获取枚举
|
||||
*/
|
||||
public static PayWayEnum findByCode(String code){
|
||||
return Arrays.stream(values())
|
||||
.filter(o -> Objects.equals(o.getCode(), code))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("该枚举不存在"));
|
||||
}
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
package cn.bootx.platform.daxpay.sdk.code;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 退款状态枚举
|
||||
* @author xxm
|
||||
* @since 2023/12/18
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum RefundStatusEnum {
|
||||
|
||||
/**
|
||||
* 接口调用成功不代表成功
|
||||
*/
|
||||
PROGRESS("progress","退款中"),
|
||||
SUCCESS("success","成功"),
|
||||
CLOSE("close","关闭"),
|
||||
FAIL("fail","失败");
|
||||
|
||||
/** 编码 */
|
||||
private final String code;
|
||||
/** 名称 */
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* 根据编码获取枚举
|
||||
*/
|
||||
public static RefundStatusEnum findByCode(String code){
|
||||
return Arrays.stream(values())
|
||||
.filter(statusEnum -> Objects.equals(statusEnum.getCode(), code))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("该枚举不存在"));
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
package cn.bootx.platform.daxpay.sdk.code;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 支付签名类型
|
||||
* @author xxm
|
||||
* @since 2023/12/24
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SignTypeEnum {
|
||||
|
||||
HMAC_SHA256("HMAC_SHA256"),
|
||||
MD5("MD5"),;
|
||||
|
||||
/** 支付方式 */
|
||||
private final String code;
|
||||
|
||||
|
||||
/**
|
||||
* 根据编码获取枚举
|
||||
*/
|
||||
public static SignTypeEnum findByCode(String code){
|
||||
return Arrays.stream(values())
|
||||
.filter(o -> Objects.equals(o.getCode(), code))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("该枚举不存在"));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
package cn.bootx.platform.daxpay.sdk.model;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayResponseModel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 支付关闭
|
||||
* @author xxm
|
||||
* @since 2024/2/2
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class PayCloseModel extends DaxPayResponseModel {
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
package cn.bootx.platform.daxpay.sdk.model;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.sdk.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayResponseModel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 支付相应对象
|
||||
* @author xxm
|
||||
* @since 2024/2/2
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class PayOrderModel extends DaxPayResponseModel {
|
||||
|
||||
/** 支付ID */
|
||||
private Long paymentId;
|
||||
|
||||
/** 是否是异步支付 */
|
||||
private boolean asyncPay;
|
||||
|
||||
/**
|
||||
* 异步支付通道
|
||||
* @see PayChannelEnum
|
||||
*/
|
||||
private String asyncChannel;
|
||||
|
||||
|
||||
/** 支付参数体(通常用于发起异步支付的参数) */
|
||||
private String payBody;
|
||||
|
||||
/**
|
||||
* 支付状态
|
||||
* @see PayStatusEnum
|
||||
*/
|
||||
private String status;
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
package cn.bootx.platform.daxpay.sdk.model;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayResponseModel;
|
||||
|
||||
/**
|
||||
* 支付退款通道明细数据
|
||||
* @author xxm
|
||||
* @since 2024/1/17
|
||||
*/
|
||||
public class RefundChannelOrderModel extends DaxPayResponseModel {
|
||||
|
||||
/** 通道 */
|
||||
private String channel;
|
||||
|
||||
/** 通道支付单id */
|
||||
private Long payChannelId;
|
||||
|
||||
/** 异步支付方式 */
|
||||
private boolean async;
|
||||
|
||||
/** 订单金额" */
|
||||
private Integer orderAmount;
|
||||
|
||||
/** 退款金额 */
|
||||
private Integer amount;
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package cn.bootx.platform.daxpay.sdk.model;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.code.RefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayResponseModel;
|
||||
|
||||
/**
|
||||
* 退款响应参数
|
||||
* @author xxm
|
||||
* @since 2023/12/18
|
||||
*/
|
||||
public class RefundModel extends DaxPayResponseModel {
|
||||
|
||||
/** 退款ID */
|
||||
private Long refundId;
|
||||
|
||||
/** 退款订单号, 如果请求时未传, 默认为退款ID */
|
||||
private String refundNo;
|
||||
|
||||
/**
|
||||
* 退款状态
|
||||
* @see RefundStatusEnum
|
||||
*/
|
||||
private String status;
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
package cn.bootx.platform.daxpay.sdk.model;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.code.RefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayResponseModel;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 退款订单数据
|
||||
* @author xxm
|
||||
* @since 2024/1/16
|
||||
*/
|
||||
public class RefundOrderResult extends DaxPayResponseModel {
|
||||
|
||||
/** 支付号 */
|
||||
private Long paymentId;
|
||||
|
||||
/** 关联的业务id */
|
||||
private String businessNo;
|
||||
|
||||
/** 退款号 */
|
||||
private String refundNo;
|
||||
|
||||
/** 标题 */
|
||||
private String title;
|
||||
|
||||
/** 退款金额 */
|
||||
private BigDecimal amount;
|
||||
|
||||
/** 剩余可退 */
|
||||
private BigDecimal refundableBalance;
|
||||
|
||||
/**
|
||||
* 异步支付通道发给网关的退款号, 用与将记录关联起来
|
||||
*/
|
||||
private String gatewayOrderNo;
|
||||
|
||||
/** 通道退款订单 */
|
||||
private List<RefundChannelOrderModel> channels;
|
||||
|
||||
/** 退款终端ip */
|
||||
private String clientIp;
|
||||
|
||||
/** 退款时间 */
|
||||
private LocalDateTime refundTime;
|
||||
|
||||
/**
|
||||
* 退款状态
|
||||
* @see RefundStatusEnum
|
||||
*/
|
||||
private String status;
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package cn.bootx.platform.daxpay.sdk.net;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.code.SignTypeEnum;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 支付配置
|
||||
* @author xxm
|
||||
* @since 2024/2/2
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
public class DaxPayConfig {
|
||||
|
||||
/** 服务地址 */
|
||||
private String serviceUrl;
|
||||
|
||||
/** 签名方式 */
|
||||
@Builder.Default
|
||||
private SignTypeEnum signType = SignTypeEnum.MD5;
|
||||
|
||||
/** 签名秘钥 */
|
||||
private String signSecret;
|
||||
|
||||
/** 请求超时时间 */
|
||||
@Builder.Default
|
||||
private int reqTimeout = 30000;
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
package cn.bootx.platform.daxpay.sdk.net;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.code.SignTypeEnum;
|
||||
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
|
||||
import cn.bootx.platform.daxpay.sdk.util.PaySignUtil;
|
||||
import cn.hutool.http.ContentType;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 支付发起工具包
|
||||
* @author xxm
|
||||
* @since 2024/2/2
|
||||
*/
|
||||
@UtilityClass
|
||||
public class DaxPayKit {
|
||||
|
||||
private DaxPayConfig config;
|
||||
|
||||
public void initConfig(DaxPayConfig config){
|
||||
DaxPayKit.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付请求执行类
|
||||
* @param request 请求参数
|
||||
* @return DaxPayResult 响应类
|
||||
* @param <T> 业务对象
|
||||
*/
|
||||
public <T extends DaxPayResponseModel> DaxPayResult<T> execute(DaxPayRequest<T> request, boolean sign){
|
||||
// 判断是是否进行签名
|
||||
if (sign) {
|
||||
if (Objects.equals(SignTypeEnum.MD5, config.getSignType())){
|
||||
String md5Sign = PaySignUtil.md5Sign(request, config.getSignSecret());
|
||||
request.setSign(md5Sign);
|
||||
} else {
|
||||
String hmacSha256Sign = PaySignUtil.hmacSha256Sign(request, config.getSignSecret());
|
||||
request.setSign(hmacSha256Sign);
|
||||
}
|
||||
}
|
||||
String data = JSONUtil.toJsonStr(request);
|
||||
String path = config.getServiceUrl() + request.path();
|
||||
HttpResponse execute = HttpUtil.createPost(path)
|
||||
.body(data, ContentType.JSON.getValue())
|
||||
.timeout(config.getReqTimeout())
|
||||
.execute();
|
||||
String body = execute.body();
|
||||
return request.toModel(body);
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
package cn.bootx.platform.daxpay.sdk.net;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 请求接口
|
||||
* @author xxm
|
||||
* @since 2024/2/2
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public abstract class DaxPayRequest<T extends DaxPayResponseModel> {
|
||||
|
||||
/** 方法请求路径 */
|
||||
public abstract String path();
|
||||
|
||||
/**
|
||||
* 将请求返回结果反序列化为实体类
|
||||
*/
|
||||
public abstract DaxPayResult<T> toModel(String json);
|
||||
|
||||
|
||||
/** 客户端ip */
|
||||
private String clientIp;
|
||||
|
||||
/** 商户扩展参数,回调时会原样返回 */
|
||||
private String attach;
|
||||
|
||||
/** 是否不进行同步通知的跳转 */
|
||||
private boolean notReturn;
|
||||
|
||||
/** 同步通知URL */
|
||||
private String returnUrl;
|
||||
|
||||
/** 是否不启用异步通知 */
|
||||
private boolean notNotify;
|
||||
|
||||
/** 异步通知地址 */
|
||||
private String notifyUrl;
|
||||
|
||||
/** 签名 */
|
||||
private String sign;
|
||||
|
||||
/** API版本号 */
|
||||
private String version = "1.0";
|
||||
|
||||
/** 请求时间,传输时间戳 */
|
||||
private Long reqTime;
|
||||
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package cn.bootx.platform.daxpay.sdk.net;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2024/2/2
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@ToString
|
||||
public abstract class DaxPayResponseModel {
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
package cn.bootx.platform.daxpay.sdk.param;
|
||||
|
||||
/**
|
||||
* 通道支付参数标识接口
|
||||
* @author xxm
|
||||
* @since 2023/12/17
|
||||
*/
|
||||
public interface ChannelParam {
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
package cn.bootx.platform.daxpay.sdk.param.channel;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.param.ChannelParam;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 支付宝支付参数
|
||||
* @author xxm
|
||||
* @since 2021/2/27
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class AliPayParam implements ChannelParam {
|
||||
|
||||
/** 授权码(主动扫描用户的付款码) */
|
||||
private String authCode;
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package cn.bootx.platform.daxpay.sdk.param.channel;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.param.ChannelParam;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 储值卡支付参数
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2022/3/14
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class VoucherPayParam implements ChannelParam {
|
||||
|
||||
/** 储值卡号 */
|
||||
private String cardNo;
|
||||
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
package cn.bootx.platform.daxpay.sdk.param.channel;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.param.ChannelParam;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 钱包支付参数
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2020/12/8
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class WalletPayParam implements ChannelParam {
|
||||
|
||||
/** 钱包ID */
|
||||
private Long walletId;
|
||||
|
||||
/** 用户ID */
|
||||
private String userId;
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package cn.bootx.platform.daxpay.sdk.param.channel;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.param.ChannelParam;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 微信支付参数
|
||||
* @author xxm
|
||||
* @since 2021/6/21
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class WeChatPayParam implements ChannelParam {
|
||||
|
||||
/** 微信openId */
|
||||
private String openId;
|
||||
|
||||
/** 授权码(主动扫描用户的付款码) */
|
||||
private String authCode;
|
||||
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
package cn.bootx.platform.daxpay.sdk.param.pay;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.sdk.code.PayWayEnum;
|
||||
import cn.bootx.platform.daxpay.sdk.param.ChannelParam;
|
||||
import cn.bootx.platform.daxpay.sdk.param.channel.AliPayParam;
|
||||
import cn.bootx.platform.daxpay.sdk.param.channel.VoucherPayParam;
|
||||
import cn.bootx.platform.daxpay.sdk.param.channel.WalletPayParam;
|
||||
import cn.bootx.platform.daxpay.sdk.param.channel.WeChatPayParam;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 同意下单支付方式参数
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2020/12/8
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class PayChannelParam {
|
||||
|
||||
/**
|
||||
* 支付通道编码
|
||||
* @see PayChannelEnum#getCode()
|
||||
*/
|
||||
private String channel;
|
||||
|
||||
/**
|
||||
* 支付方式编码
|
||||
* @see PayWayEnum#getCode()
|
||||
*/
|
||||
private String way;
|
||||
|
||||
/** 支付金额 */
|
||||
private Integer amount;
|
||||
|
||||
/**
|
||||
* 附加支付参数, 传输json格式字符串
|
||||
* @see AliPayParam
|
||||
* @see WeChatPayParam
|
||||
* @see VoucherPayParam
|
||||
* @see WalletPayParam
|
||||
*/
|
||||
private ChannelParam channelParam;
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
package cn.bootx.platform.daxpay.sdk.param.pay;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.model.PayCloseModel;
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayRequest;
|
||||
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 支付关闭参数
|
||||
* @author xxm
|
||||
* @since 2023/12/17
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class PayCloseParam extends DaxPayRequest<PayCloseModel> {
|
||||
|
||||
/** 支付单ID */
|
||||
private Long paymentId;
|
||||
|
||||
/** 业务号 */
|
||||
private String businessNo;
|
||||
|
||||
/**
|
||||
* 方法请求路径
|
||||
*/
|
||||
@Override
|
||||
public String path() {
|
||||
return "/unipay/close";
|
||||
}
|
||||
|
||||
/**
|
||||
* 将请求返回结果反序列化为实体类
|
||||
*/
|
||||
@Override
|
||||
public DaxPayResult<PayCloseModel> toModel(String json) {
|
||||
return JSONUtil.toBean(json, new TypeReference<DaxPayResult<PayCloseModel>>() {}, false);
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package cn.bootx.platform.daxpay.sdk.param.pay;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.model.PayOrderModel;
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayRequest;
|
||||
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 支付参数
|
||||
* @author xxm
|
||||
* @since 2024/2/2
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class PayParam extends DaxPayRequest<PayOrderModel> {
|
||||
|
||||
/** 业务号 */
|
||||
private String businessNo;
|
||||
|
||||
/** 支付标题 */
|
||||
private String title;
|
||||
|
||||
/** 支付描述 */
|
||||
private String description;
|
||||
|
||||
/** 过期时间, 多次传输以第一次为准 */
|
||||
private Long expiredTime;
|
||||
|
||||
/** 用户付款中途退出返回商户网站的地址(部分支付场景中可用) */
|
||||
private String quitUrl;
|
||||
|
||||
/** 支付通道信息参数 */
|
||||
private List<PayChannelParam> payChannels;
|
||||
|
||||
/**
|
||||
* 方法请求路径
|
||||
*/
|
||||
@Override
|
||||
public String path() {
|
||||
return "/unipay/pay";
|
||||
}
|
||||
|
||||
/**
|
||||
* 将请求返回结果反序列化为实体类
|
||||
*/
|
||||
@Override
|
||||
public DaxPayResult<PayOrderModel> toModel(String json) {
|
||||
return JSONUtil.toBean(json, new TypeReference<DaxPayResult<PayOrderModel>>() {}, false);
|
||||
}
|
||||
}
|
@@ -0,0 +1,82 @@
|
||||
package cn.bootx.platform.daxpay.sdk.param.pay;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.sdk.code.PayWayEnum;
|
||||
import cn.bootx.platform.daxpay.sdk.model.PayOrderModel;
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayRequest;
|
||||
import cn.bootx.platform.daxpay.sdk.param.ChannelParam;
|
||||
import cn.bootx.platform.daxpay.sdk.param.channel.AliPayParam;
|
||||
import cn.bootx.platform.daxpay.sdk.param.channel.VoucherPayParam;
|
||||
import cn.bootx.platform.daxpay.sdk.param.channel.WalletPayParam;
|
||||
import cn.bootx.platform.daxpay.sdk.param.channel.WeChatPayParam;
|
||||
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 简单支付请求参数
|
||||
* @author xxm
|
||||
* @since 2024/2/2
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class SimplePayParam extends DaxPayRequest<PayOrderModel> {
|
||||
|
||||
/** 业务号 */
|
||||
private String businessNo;
|
||||
|
||||
/** 支付标题 */
|
||||
private String title;
|
||||
|
||||
/** 支付描述 */
|
||||
private String description;
|
||||
|
||||
/** 过期时间 */
|
||||
private Long expiredTime;
|
||||
|
||||
/** 用户付款中途退出返回商户网站的地址(部分支付场景中可用) */
|
||||
private String quitUrl;
|
||||
|
||||
/**
|
||||
* @see PayChannelEnum#getCode()
|
||||
*/
|
||||
private String channel;
|
||||
|
||||
/**
|
||||
* 支付方式编码
|
||||
* @see PayWayEnum#getCode()
|
||||
*/
|
||||
private String payWay;
|
||||
|
||||
/** 支付金额 */
|
||||
private Integer amount;
|
||||
|
||||
/**
|
||||
* 附加支付参数
|
||||
* @see AliPayParam
|
||||
* @see WeChatPayParam
|
||||
* @see VoucherPayParam
|
||||
* @see WalletPayParam
|
||||
*/
|
||||
private ChannelParam channelParam;
|
||||
|
||||
/**
|
||||
* 请求路径
|
||||
*/
|
||||
@Override
|
||||
public String path() {
|
||||
return "/unipay/simplePay";
|
||||
}
|
||||
|
||||
/**
|
||||
* 将请求返回结果反序列化为实体类
|
||||
*/
|
||||
@Override
|
||||
public DaxPayResult<PayOrderModel> toModel(String json) {
|
||||
return JSONUtil.toBean(json, new TypeReference<DaxPayResult<PayOrderModel>>() {}, false);
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package cn.bootx.platform.daxpay.sdk.param.refund;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.code.PayChannelEnum;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 分通道退款参数
|
||||
* @author xxm
|
||||
* @since 2023/12/18
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class RefundChannelParam {
|
||||
|
||||
/**
|
||||
* 支付通道编码
|
||||
* @see PayChannelEnum#getCode()
|
||||
*/
|
||||
private String channel;
|
||||
|
||||
/**
|
||||
* 退款金额
|
||||
*/
|
||||
private Integer amount;
|
||||
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
package cn.bootx.platform.daxpay.sdk.param.refund;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.model.RefundModel;
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayRequest;
|
||||
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 退款参数,适用于组合支付的订单退款操作中,
|
||||
* @author xxm
|
||||
* @since 2023/12/18
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class RefundParam extends DaxPayRequest<RefundModel> {
|
||||
|
||||
/** 支付单ID */
|
||||
private Long paymentId;
|
||||
|
||||
/** 业务号 */
|
||||
private String businessNo;
|
||||
|
||||
/**
|
||||
* 部分退款需要传输支付通道参数参数
|
||||
*/
|
||||
private boolean refundAll;
|
||||
|
||||
/**
|
||||
* 退款号可以为空, 但不可以重复, 如果退款号为空, 则系统会自动生成退款号, 与退款ID一致
|
||||
*/
|
||||
private String refundNo;
|
||||
|
||||
/**
|
||||
* 部分退款时必传
|
||||
*/
|
||||
private List<RefundChannelParam> refundChannels;
|
||||
|
||||
/** 退款原因 */
|
||||
private String reason;
|
||||
|
||||
/**
|
||||
* 方法请求路径
|
||||
*/
|
||||
@Override
|
||||
public String path() {
|
||||
return "/unipay/refund";
|
||||
}
|
||||
|
||||
/**
|
||||
* 将请求返回结果反序列化为实体类
|
||||
*/
|
||||
@Override
|
||||
public DaxPayResult<RefundModel> toModel(String json) {
|
||||
return JSONUtil.toBean(json, new TypeReference<DaxPayResult<RefundModel>>() {}, false);
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
package cn.bootx.platform.daxpay.sdk.param.refund;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.model.RefundModel;
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayRequest;
|
||||
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 简单退款参数,只可以用于非组合的支付订单
|
||||
* @author xxm
|
||||
* @since 2023/12/18
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class SimpleRefundParam extends DaxPayRequest<RefundModel> {
|
||||
|
||||
/**
|
||||
* 支付单ID, 优先级高于业务号
|
||||
*/
|
||||
private Long paymentId;
|
||||
|
||||
/** 业务号 */
|
||||
private String businessNo;
|
||||
|
||||
/**
|
||||
* 退款号可以为空, 但不可以重复, 如果退款号为空, 则系统会自动生成退款号, 与退款ID一致
|
||||
*/
|
||||
private String refundNo;
|
||||
|
||||
/**
|
||||
* 是否全部退款, 部分退款需要传输refundModes参数
|
||||
*/
|
||||
private boolean refundAll;
|
||||
|
||||
/** 退款金额 */
|
||||
private Integer amount;
|
||||
|
||||
/** 退款原因 */
|
||||
private String reason;
|
||||
|
||||
/**
|
||||
* 方法请求路径
|
||||
*/
|
||||
@Override
|
||||
public String path() {
|
||||
return "/unipay/simpleRefund";
|
||||
}
|
||||
|
||||
/**
|
||||
* 将请求返回结果反序列化为实体类
|
||||
*/
|
||||
@Override
|
||||
public DaxPayResult<RefundModel> toModel(String json) {
|
||||
return JSONUtil.toBean(json, new TypeReference<DaxPayResult<RefundModel>>() {}, false);
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package cn.bootx.platform.daxpay.sdk.response;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayResponseModel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2024/2/2
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class DaxPayResult<T extends DaxPayResponseModel> {
|
||||
|
||||
/** 提示信息 */
|
||||
private String msg = "success";
|
||||
|
||||
/** 响应码 */
|
||||
private int code = 0;
|
||||
|
||||
/** 响应体 */
|
||||
private T data;
|
||||
|
||||
/** 数据签名 */
|
||||
private String sign;
|
||||
}
|
@@ -0,0 +1,185 @@
|
||||
package cn.bootx.platform.daxpay.sdk.util;
|
||||
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.crypto.digest.HmacAlgorithm;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
/**
|
||||
* 如果需要进行签名,
|
||||
* 1. 参数名ASCII码从小到大排序(字典序)
|
||||
* 2. 如果参数的值为空不参与签名
|
||||
* 3. 参数名不区分大小写
|
||||
* 4. 嵌套对象转换成先转换成MAP再序列化为字符串
|
||||
* 5. 支持两层嵌套, 更多层级嵌套未测试, 可能会导致不可预知的问题
|
||||
*/
|
||||
@UtilityClass
|
||||
public class PaySignUtil {
|
||||
|
||||
/**
|
||||
* 将参数转换为map对象. 使用ChatGPT生成
|
||||
* 1. 参数名ASCII码从小到大排序(字典序)
|
||||
* 2. 如果参数的值为空不参与签名;
|
||||
* 3. 参数名不区分大小写;
|
||||
*/
|
||||
public Map<String, String> toMap(Object object) {
|
||||
Map<String, String> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
toMap(object, map);
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将参数转换为map对象. 使用ChatGPT生成, 仅局限于对请求支付相关参数进行签名
|
||||
*/
|
||||
@SneakyThrows
|
||||
private void toMap(Object object, Map<String, String> map) {
|
||||
Class<?> clazz = object.getClass();
|
||||
while (clazz != null) {
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
String fieldName = field.getName();
|
||||
Object fieldValue = field.get(object);
|
||||
if (fieldValue != null) {
|
||||
// 基础类型及包装类 和 字符串类型
|
||||
if (ClassUtil.isBasicType(field.getType())|| field.getType().equals(String.class)) {
|
||||
String fieldValueString = String.valueOf(fieldValue);
|
||||
map.put(fieldName, fieldValueString);
|
||||
}
|
||||
// 集合类型
|
||||
else if (Collection.class.isAssignableFrom(field.getType())) {
|
||||
Collection<?> collection = (Collection<?>) fieldValue;
|
||||
if (!collection.isEmpty()) {
|
||||
List<Map<String, String>> maps = collection.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(item -> {
|
||||
Map<String, String> nestedMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
toMap(item, nestedMap);
|
||||
return nestedMap;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
map.put(fieldName, JSONUtil.toJsonStr(maps));
|
||||
}
|
||||
// 其他类型
|
||||
} else {
|
||||
Map<String, String> nestedMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
toMap(fieldValue, nestedMap);
|
||||
String nestedJson = JSONUtil.toJsonStr(map);
|
||||
map.put(fieldName, nestedJson);
|
||||
}
|
||||
}
|
||||
}
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 把所有元素排序, 并拼接成字符, 用于签名
|
||||
*/
|
||||
public static String createLinkString(Map<String, String> params) {
|
||||
String connStr = "&";
|
||||
List<String> keys = new ArrayList<>(params.keySet());
|
||||
Collections.sort(keys);
|
||||
StringBuilder content = new StringBuilder();
|
||||
for (int i = 0; i < keys.size(); i++) {
|
||||
String key = keys.get(i);
|
||||
String value = params.get(key);
|
||||
// 拼接时,不包括最后一个&字符
|
||||
if (i == keys.size() - 1) {
|
||||
content.append(key)
|
||||
.append("=")
|
||||
.append(value);
|
||||
} else {
|
||||
content.append(key)
|
||||
.append("=")
|
||||
.append(value)
|
||||
.append(connStr);
|
||||
}
|
||||
}
|
||||
return content.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成16进制 MD5 字符串
|
||||
*
|
||||
* @param data 数据
|
||||
* @return MD5 字符串
|
||||
*/
|
||||
public String md5(String data) {
|
||||
return SecureUtil.md5(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成16进制的 sha256 字符串
|
||||
*
|
||||
* @param data 数据
|
||||
* @param signKey 密钥
|
||||
* @return sha256 字符串
|
||||
*/
|
||||
public String hmacSha256(String data, String signKey) {
|
||||
return SecureUtil.hmac(HmacAlgorithm.HmacSHA256, signKey).digestHex(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成待签名字符串
|
||||
* @param object 待签名对象
|
||||
* @param signKey 签名Key
|
||||
* @return 待签名字符串
|
||||
*/
|
||||
public String signString(Object object, String signKey){
|
||||
// 签名
|
||||
Map<String, String> map = toMap(object);
|
||||
// 生成签名前先去除sign参数
|
||||
map.remove("sign");
|
||||
// 创建待签名字符串
|
||||
String data = createLinkString(map);
|
||||
// 将签名key追加到字符串最后
|
||||
return data + "&key=" + signKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* md5方式进行签名
|
||||
*
|
||||
* @return 签名值
|
||||
*/
|
||||
public String md5Sign(Object object, String signKey){
|
||||
String data = signString(object, signKey);
|
||||
return md5(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* hmacSha256方式进行签名
|
||||
*
|
||||
* @return 签名值
|
||||
*/
|
||||
public String hmacSha256Sign(Object object, String signKey){
|
||||
String data = signString(object, signKey);
|
||||
return hmacSha256(data, signKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* MD5签名验证
|
||||
*/
|
||||
public boolean verifyMd5Sign(Object object, String signKey, String sign){
|
||||
String md5Sign = md5Sign(object, signKey);
|
||||
return md5Sign.equals(sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* hmacSha256签名验证
|
||||
*/
|
||||
public boolean verifyHmacSha256Sign(Object object, String signKey, String sign){
|
||||
String hmacSha256Sign = hmacSha256Sign(object, signKey);
|
||||
return hmacSha256Sign.equals(sign);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package cn.bootx.platform.daxpay.sdk;
|
||||
|
||||
import cn.bootx.platform.daxpay.sdk.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.sdk.code.PayWayEnum;
|
||||
import cn.bootx.platform.daxpay.sdk.model.PayOrderModel;
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayConfig;
|
||||
import cn.bootx.platform.daxpay.sdk.net.DaxPayKit;
|
||||
import cn.bootx.platform.daxpay.sdk.param.pay.SimplePayParam;
|
||||
import cn.bootx.platform.daxpay.sdk.response.DaxPayResult;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2024/2/2
|
||||
*/
|
||||
public class SimplePayOrderTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
DaxPayConfig config = DaxPayConfig.builder()
|
||||
.serviceUrl("http://127.0.0.1:9000")
|
||||
.signSecret("123456")
|
||||
.build();
|
||||
DaxPayKit.initConfig(config);
|
||||
|
||||
// 简单支付参数
|
||||
SimplePayParam param = new SimplePayParam();
|
||||
param.setBusinessNo("1");
|
||||
param.setAmount(1);
|
||||
param.setTitle("测试接口支付");
|
||||
param.setChannel(PayChannelEnum.ALI.getCode());
|
||||
param.setPayWay(PayWayEnum.QRCODE.getCode());
|
||||
param.setClientIp("127.0.0.1");
|
||||
param.setNotNotify(true);
|
||||
param.setNotReturn(true);
|
||||
|
||||
DaxPayResult<PayOrderModel> execute = DaxPayKit.execute(param, true);
|
||||
System.out.println(execute);
|
||||
}
|
||||
}
|
@@ -5,5 +5,5 @@ package cn.bootx.platform.daxpay.param;
|
||||
* @author xxm
|
||||
* @since 2023/12/17
|
||||
*/
|
||||
public interface IChannelParam {
|
||||
public interface ChannelParam {
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.param.channel;
|
||||
|
||||
import cn.bootx.platform.daxpay.param.IChannelParam;
|
||||
import cn.bootx.platform.daxpay.param.ChannelParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -10,7 +10,7 @@ import lombok.Data;
|
||||
*/
|
||||
@Data
|
||||
@Schema(title = "支付宝支付参数")
|
||||
public class AliPayParam implements IChannelParam {
|
||||
public class AliPayParam implements ChannelParam {
|
||||
|
||||
@Schema(description = "授权码(主动扫描用户的付款码)")
|
||||
private String authCode;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.param.channel;
|
||||
|
||||
import cn.bootx.platform.daxpay.param.IChannelParam;
|
||||
import cn.bootx.platform.daxpay.param.ChannelParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -12,7 +12,7 @@ import lombok.Data;
|
||||
*/
|
||||
@Data
|
||||
@Schema(title = "储值卡支付参数")
|
||||
public class VoucherPayParam implements IChannelParam {
|
||||
public class VoucherPayParam implements ChannelParam {
|
||||
|
||||
@Schema(description = "储值卡号")
|
||||
private String cardNo;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.param.channel;
|
||||
|
||||
import cn.bootx.platform.daxpay.param.IChannelParam;
|
||||
import cn.bootx.platform.daxpay.param.ChannelParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -12,7 +12,7 @@ import lombok.Data;
|
||||
*/
|
||||
@Data
|
||||
@Schema(title = "钱包支付参数")
|
||||
public class WalletPayParam implements IChannelParam {
|
||||
public class WalletPayParam implements ChannelParam {
|
||||
|
||||
@Schema(description = "钱包ID")
|
||||
private Long walletId;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.param.channel;
|
||||
|
||||
import cn.bootx.platform.daxpay.param.IChannelParam;
|
||||
import cn.bootx.platform.daxpay.param.ChannelParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -10,7 +10,7 @@ import lombok.Data;
|
||||
*/
|
||||
@Data
|
||||
@Schema(title = "微信支付参数")
|
||||
public class WeChatPayParam implements IChannelParam {
|
||||
public class WeChatPayParam implements ChannelParam {
|
||||
|
||||
@Schema(description = "微信openId")
|
||||
private String openId;
|
||||
|
@@ -48,5 +48,5 @@ public class PayChannelParam {
|
||||
* @see WalletPayParam
|
||||
*/
|
||||
@Schema(description = "附加支付参数")
|
||||
private String channelExtra;
|
||||
private String channelParam;
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ import java.time.LocalDateTime;
|
||||
public abstract class PayCommonParam {
|
||||
|
||||
/** 客户端ip */
|
||||
@NotBlank(message = "客户端ip不可为空")
|
||||
// @NotBlank(message = "客户端ip不可为空")
|
||||
@Schema(description = "客户端ip")
|
||||
private String clientIp;
|
||||
|
||||
@@ -48,12 +48,12 @@ public abstract class PayCommonParam {
|
||||
|
||||
/** API版本号 */
|
||||
@Schema(description = "API版本号")
|
||||
@NotBlank(message = "API版本号必填")
|
||||
// @NotBlank(message = "API版本号必填")
|
||||
private String version = "1.0.0";
|
||||
|
||||
/** 请求时间,时间戳转时间 */
|
||||
@Schema(description = "请求时间,传输时间戳")
|
||||
@NotNull(message = "请求时间必填")
|
||||
// @NotNull(message = "请求时间必填")
|
||||
@JsonDeserialize(using = TimestampToLocalDateTimeDeserializer.class)
|
||||
private LocalDateTime reqTime;
|
||||
|
||||
|
@@ -50,7 +50,7 @@ public class SimplePayParam extends PayCommonParam{
|
||||
*/
|
||||
@Schema(description = "支付通道编码")
|
||||
@NotBlank(message = "支付通道编码不可为空")
|
||||
private String payChannel;
|
||||
private String channel;
|
||||
|
||||
/**
|
||||
* @see PayWayEnum#getCode()
|
||||
@@ -70,8 +70,8 @@ public class SimplePayParam extends PayCommonParam{
|
||||
* @see VoucherPayParam
|
||||
* @see WalletPayParam
|
||||
*/
|
||||
@Schema(description = "附加支付参数")
|
||||
private String channelExtra;
|
||||
@Schema(description = "附加通道支付参数")
|
||||
private String channelParam;
|
||||
|
||||
|
||||
}
|
||||
|
@@ -14,6 +14,6 @@ import org.slf4j.MDC;
|
||||
@Schema(title = "支付通用返回参数")
|
||||
public class CommonResult {
|
||||
|
||||
@Schema(description = "请求ID")
|
||||
private String reqId = MDC.get(CommonCode.TRACE_ID);
|
||||
@Schema(description = "追踪ID")
|
||||
private String traceId = MDC.get(CommonCode.TRACE_ID);
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ public class PayResult extends CommonResult {
|
||||
* @see PayChannelEnum#ASYNC_TYPE_CODE
|
||||
*/
|
||||
@Schema(description = "异步支付通道")
|
||||
private String asyncPayChannel;
|
||||
private String asyncChannel;
|
||||
|
||||
|
||||
/** 支付参数体(通常用于发起异步支付的参数) */
|
||||
|
@@ -22,4 +22,7 @@ public class RefundResult extends CommonResult {
|
||||
|
||||
@Schema(description = "退款订单号, 如果请求时未传, 则默认使用退款ID")
|
||||
private String refundNo;
|
||||
|
||||
@Schema(description = "退款状态")
|
||||
private String status;
|
||||
}
|
||||
|
@@ -153,7 +153,7 @@ public class PaySignUtil {
|
||||
// 创建待签名字符串
|
||||
String data = createLinkString(map);
|
||||
// 将签名key追加到字符串最后
|
||||
return "&key=" + signKey;
|
||||
return data + "&key=" + signKey;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -46,7 +46,7 @@ public class VoucherPayService {
|
||||
VoucherPayParam voucherPayParam;
|
||||
try {
|
||||
// 储值卡参数验证
|
||||
String extraParamsJson = payChannelParam.getChannelExtra();
|
||||
String extraParamsJson = payChannelParam.getChannelParam();
|
||||
if (StrUtil.isNotBlank(extraParamsJson)) {
|
||||
voucherPayParam = JSONUtil.toBean(extraParamsJson, VoucherPayParam.class);
|
||||
} else {
|
||||
|
@@ -32,7 +32,7 @@ public class PayNoticeResult {
|
||||
* @see PayChannelEnum#ASYNC_TYPE_CODE
|
||||
*/
|
||||
@Schema(description = "异步支付通道")
|
||||
private String asyncPayChannel;
|
||||
private String asyncChannel;
|
||||
|
||||
@Schema(description = "支付金额")
|
||||
private Integer amount;
|
||||
|
@@ -97,7 +97,7 @@ public class PayBuilder {
|
||||
.setPayWay(channelParam.getWay())
|
||||
.setAmount(channelParam.getAmount())
|
||||
.setRefundableBalance(channelParam.getAmount())
|
||||
.setChannelExtra(channelParam.getChannelExtra());
|
||||
.setChannelExtra(channelParam.getChannelParam());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,7 +126,7 @@ public class PayBuilder {
|
||||
paymentResult = new PayResult();
|
||||
paymentResult.setPaymentId(payOrder.getId());
|
||||
paymentResult.setAsyncPay(payOrder.isAsyncPay());
|
||||
paymentResult.setAsyncPayChannel(payOrder.getAsyncChannel());
|
||||
paymentResult.setAsyncChannel(payOrder.getAsyncChannel());
|
||||
paymentResult.setStatus(payOrder.getStatus());
|
||||
|
||||
// 设置异步支付参数
|
||||
|
@@ -68,7 +68,7 @@ public class PayChannelOrderService {
|
||||
.setAmount(payChannelParam.getAmount())
|
||||
.setRefundableBalance(payChannelParam.getAmount())
|
||||
.setPayTime(LocalDateTime.now())
|
||||
.setChannelExtra(payChannelParam.getChannelExtra())
|
||||
.setChannelExtra(payChannelParam.getChannelParam())
|
||||
.setStatus(payStatus.getCode());
|
||||
channelOrderManager.deleteByPaymentIdAndAsync(payOrder.getId());
|
||||
channelOrderManager.save(payChannelOrder);
|
||||
@@ -77,7 +77,7 @@ public class PayChannelOrderService {
|
||||
payOrderChannelOpt.get()
|
||||
.setPayWay(payChannelParam.getWay())
|
||||
.setPayTime(LocalDateTime.now())
|
||||
.setChannelExtra(payChannelParam.getChannelExtra())
|
||||
.setChannelExtra(payChannelParam.getChannelParam())
|
||||
.setStatus(payStatus.getCode());
|
||||
channelOrderManager.updateById(payOrderChannelOpt.get());
|
||||
}
|
||||
|
@@ -85,6 +85,7 @@ public class PayAssistService {
|
||||
asyncPayInfo.setExpiredTime(payParam.getExpiredTime());
|
||||
return;
|
||||
}
|
||||
// 读取本地时间
|
||||
LocalDateTime paymentExpiredTime = PayUtil.getPaymentExpiredTime(platform.getOrderTimeout());
|
||||
asyncPayInfo.setExpiredTime(paymentExpiredTime);
|
||||
}
|
||||
|
@@ -102,10 +102,10 @@ public class PayService {
|
||||
// 组装支付参数
|
||||
PayParam payParam = new PayParam();
|
||||
PayChannelParam payChannelParam = new PayChannelParam();
|
||||
payChannelParam.setChannel(simplePayParam.getPayChannel());
|
||||
payChannelParam.setChannel(simplePayParam.getChannel());
|
||||
payChannelParam.setWay(simplePayParam.getPayWay());
|
||||
payChannelParam.setAmount(simplePayParam.getAmount());
|
||||
payChannelParam.setChannelExtra(simplePayParam.getChannelExtra());
|
||||
payChannelParam.setChannelParam(simplePayParam.getChannelParam());
|
||||
BeanUtil.copyProperties(simplePayParam,payParam, CopyOptions.create().ignoreNullValue());
|
||||
payParam.setPayChannels(Collections.singletonList(payChannelParam));
|
||||
// 复用支付下单接口
|
||||
|
@@ -52,7 +52,7 @@ public class AliPayStrategy extends AbsPayStrategy {
|
||||
public void doBeforePayHandler() {
|
||||
try {
|
||||
// 支付宝参数验证
|
||||
String extraParamsJson = this.getPayChannelParam().getChannelExtra();
|
||||
String extraParamsJson = this.getPayChannelParam().getChannelParam();
|
||||
if (StrUtil.isNotBlank(extraParamsJson)) {
|
||||
this.aliPayParam = JSONUtil.toBean(extraParamsJson, AliPayParam.class);
|
||||
}
|
||||
|
@@ -54,7 +54,7 @@ public class WalletPayStrategy extends AbsPayStrategy {
|
||||
WalletPayParam walletPayParam = new WalletPayParam();
|
||||
try {
|
||||
// 钱包参数验证
|
||||
String extraParamsJson = this.getPayChannelParam().getChannelExtra();
|
||||
String extraParamsJson = this.getPayChannelParam().getChannelParam();
|
||||
if (StrUtil.isNotBlank(extraParamsJson)) {
|
||||
walletPayParam = JSONUtil.toBean(extraParamsJson, WalletPayParam.class);
|
||||
}
|
||||
|
@@ -55,7 +55,7 @@ public class WeChatPayStrategy extends AbsPayStrategy {
|
||||
public void doBeforePayHandler() {
|
||||
try {
|
||||
// 微信参数验证
|
||||
String extraParamsJson = this.getPayChannelParam().getChannelExtra();
|
||||
String extraParamsJson = this.getPayChannelParam().getChannelParam();
|
||||
if (StrUtil.isNotBlank(extraParamsJson)) {
|
||||
this.weChatPayParam = JSONUtil.toBean(extraParamsJson, WeChatPayParam.class);
|
||||
}
|
||||
|
@@ -42,7 +42,7 @@ public class PayCallbackRecord extends MpCreateEntity implements EntityBaseFunct
|
||||
* @see PayChannelEnum#getCode()
|
||||
*/
|
||||
@DbColumn(comment = "支付通道")
|
||||
private String payChannel;
|
||||
private String channel;
|
||||
|
||||
/**
|
||||
* 回调类型
|
||||
|
@@ -30,7 +30,7 @@ public class PayCallbackRecordDto extends BaseDto {
|
||||
* @see PayChannelEnum#getCode()
|
||||
*/
|
||||
@Schema(description = "支付通道")
|
||||
private String payChannel;
|
||||
private String channel;
|
||||
|
||||
/**
|
||||
* 回调类型
|
||||
|
@@ -109,7 +109,7 @@ public abstract class AbsCallbackStrategy implements PayStrategy {
|
||||
.orElse(null);
|
||||
|
||||
PayCallbackRecord payNotifyRecord = new PayCallbackRecord()
|
||||
.setPayChannel(this.getChannel().getCode())
|
||||
.setChannel(this.getChannel().getCode())
|
||||
.setNotifyInfo(JSONUtil.toJsonStr(callbackInfo.getCallbackParam()))
|
||||
.setOrderId(callbackInfo.getOrderId())
|
||||
.setGatewayOrderNo(callbackInfo.getGatewayOrderNo())
|
||||
|
@@ -30,13 +30,12 @@ public class PayCallbackRecordQuery extends QueryOrder {
|
||||
* @see PayChannelEnum#getCode()
|
||||
*/
|
||||
@Schema(description = "支付通道")
|
||||
private String payChannel;
|
||||
private String channel;
|
||||
|
||||
|
||||
/**
|
||||
* 回调处理状态
|
||||
* @see PayCallbackStatusEnum
|
||||
* @see RefundCallbackStatusEnum
|
||||
*/
|
||||
@Schema(description = "回调处理状态")
|
||||
private String status;
|
||||
|
@@ -40,7 +40,7 @@ class PaymentSignServiceTest {
|
||||
p1.setWay("wx_app");
|
||||
AliPayParam aliPayParam = new AliPayParam();
|
||||
aliPayParam.setAuthCode("6688");
|
||||
p1.setChannelExtra(JSONUtil.toJsonStr(aliPayParam));
|
||||
p1.setChannelParam(JSONUtil.toJsonStr(aliPayParam));
|
||||
|
||||
PayChannelParam p2 = new PayChannelParam();
|
||||
p2.setAmount(100);
|
||||
@@ -49,7 +49,7 @@ class PaymentSignServiceTest {
|
||||
WeChatPayParam weChatPayParam = new WeChatPayParam();
|
||||
weChatPayParam.setOpenId("w2qsz2xawe3gbhyyff28fs01fd");
|
||||
weChatPayParam.setAuthCode("8866");
|
||||
p2.setChannelExtra(JSONUtil.toJsonStr(weChatPayParam));
|
||||
p2.setChannelParam(JSONUtil.toJsonStr(weChatPayParam));
|
||||
List<PayChannelParam> payWays = Arrays.asList(p1, p2);
|
||||
payParam.setPayChannels(payWays);
|
||||
|
||||
|
Reference in New Issue
Block a user