mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-07 21:17:42 +00:00
feat 签名算法支持嵌套参数优化, 新增支付演示模块
This commit is contained in:
@@ -70,7 +70,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>daxpay-single-core</artifactId>
|
||||
<version>${dax.version}</version>
|
||||
<version>${daxpay.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 支付宝支付 -->
|
||||
@@ -109,6 +109,7 @@
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- 分布式锁 -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>lock4j-redis-template-spring-boot-starter</artifactId>
|
||||
|
@@ -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<String, Object> channelParam = payChannelParam.getChannelParam();
|
||||
if (CollUtil.isNotEmpty(channelParam)) {
|
||||
voucherPayParam = BeanUtil.toBean(channelParam, VoucherPayParam.class);
|
||||
} else {
|
||||
throw new PayFailureException("储值卡支付参数错误");
|
||||
}
|
||||
|
@@ -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<RefundableInfo> buildRefundableInfo(List<PayChannelParam> payChannelParamList) {
|
||||
if (CollectionUtil.isEmpty(payChannelParamList)) {
|
||||
return Collections.emptyList();
|
||||
Map<String, Object> 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;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
/**
|
||||
|
@@ -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<PayChannelOrder> payOrderChannelOpt = channelOrderManager.findByPaymentIdAndChannel(payOrder.getId(), payChannelParam.getChannel());
|
||||
// 扩展信息处理
|
||||
Map<String, Object> 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());
|
||||
}
|
||||
|
@@ -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<String, Object> channelParam = this.getPayChannelParam().getChannelParam();
|
||||
if (CollUtil.isNotEmpty(channelParam)) {
|
||||
this.aliPayParam = BeanUtil.toBean(channelParam, AliPayParam.class);
|
||||
}
|
||||
else {
|
||||
this.aliPayParam = new AliPayParam();
|
||||
|
@@ -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<String, Object> channelParam = this.getPayChannelParam().getChannelParam();
|
||||
if (CollUtil.isNotEmpty(channelParam)) {
|
||||
walletPayParam = BeanUtil.toBean(channelParam, WalletPayParam.class);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
throw new PayFailureException("支付参数错误");
|
||||
|
@@ -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<String, Object> channelParam = this.getPayChannelParam().getChannelParam();
|
||||
if (CollUtil.isNotEmpty(channelParam)) {
|
||||
this.weChatPayParam = BeanUtil.toBean(channelParam, WeChatPayParam.class);
|
||||
} else {
|
||||
this.weChatPayParam = new WeChatPayParam();
|
||||
}
|
||||
|
||||
// 检查金额
|
||||
|
@@ -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);
|
||||
|
@@ -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<PayChannelParam> 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<String, String> 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));
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user