feat: 新增vm支付
This commit is contained in:
parent
497b3b9c80
commit
cbd461a1c4
|
|
@ -5,6 +5,7 @@ import com.ruoyi.ai.service.IAiRechargeService;
|
|||
import com.ruoyi.ai.service.IJinShaService;
|
||||
import com.ruoyi.ai.service.IKaDaService;
|
||||
import com.ruoyi.ai.service.IYuZhouService;
|
||||
import com.ruoyi.ai.service.IVmService;
|
||||
import com.ruoyi.common.annotation.Anonymous;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import io.swagger.annotations.Api;
|
||||
|
|
@ -25,6 +26,7 @@ public class PayController {
|
|||
private final IKaDaService kaDaService;
|
||||
private final IAiRechargeService aiRechargeService;
|
||||
private final IYuZhouService yuZhouService;
|
||||
private final IVmService vmService;
|
||||
|
||||
/**
|
||||
* jinsha请求支付
|
||||
|
|
@ -85,4 +87,22 @@ public class PayController {
|
|||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* VM请求支付
|
||||
*/
|
||||
@PostMapping("/vm-pay")
|
||||
@ApiOperation("VM请求支付")
|
||||
public AjaxResult vmPay(@RequestBody VmPayReq req) throws Exception {
|
||||
PayResVO payResVO = vmService.vmPay(req.getGearId(), req.getVmCardInfo());
|
||||
return AjaxResult.success(payResVO);
|
||||
}
|
||||
|
||||
@PostMapping("/vm-callBack")
|
||||
@ApiOperation("VM支付回调")
|
||||
@Anonymous
|
||||
public AjaxResult vmCallBack(@RequestBody VmCallBackReq req) {
|
||||
AjaxResult ajaxResult = vmService.vmCallBack(req);
|
||||
return ajaxResult;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,6 +244,18 @@ yuzhou:
|
|||
redirectUrl: www.google.com
|
||||
callbackUrl: www.google.com
|
||||
|
||||
# VM支付配置
|
||||
vm:
|
||||
url: http://payment-api.togame.top
|
||||
mchNo: M1768983012
|
||||
appId: 697089e4f41a4f456f159408
|
||||
secret: 120tzr4snoq11yus8la9gx7cbutw1uore4pervckvqmsswrt1hl9qkd0ug5r6twwv94jex03ajpsmsky2za4x1kghd2l54z4nn7t5fcy4gewsvwjjxrce5q1f7u2yeqj
|
||||
notifyUrl: www.google.com
|
||||
# 支付方式,固定为BUZHI_VM(国际VM卡支付)
|
||||
wayCode: BUZHI_VM
|
||||
# 货币代码,默认USD
|
||||
currency: USD
|
||||
|
||||
# 汇率服务配置
|
||||
exchange-rate:
|
||||
enabled: true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
package com.ruoyi.ai.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* VM支付回调请求
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-XX
|
||||
*/
|
||||
@Data
|
||||
public class VmCallBackReq {
|
||||
|
||||
/**
|
||||
* 商户号
|
||||
*/
|
||||
private String mchNo;
|
||||
|
||||
/**
|
||||
* 应用ID
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
private String mchOrderNo;
|
||||
|
||||
/**
|
||||
* 支付订单号
|
||||
*/
|
||||
private String payOrderId;
|
||||
|
||||
/**
|
||||
* 支付方式
|
||||
*/
|
||||
private String wayCode;
|
||||
|
||||
/**
|
||||
* 支付金额,单位分
|
||||
*/
|
||||
private Integer amount;
|
||||
|
||||
/**
|
||||
* 货币代码
|
||||
*/
|
||||
private String currency;
|
||||
|
||||
/**
|
||||
* 订单状态:0-订单生成, 1-支付中, 2-支付成功, 3-支付失败, 4-已撤销, 5-已退款, 6-订单关闭
|
||||
*/
|
||||
private Integer orderState;
|
||||
|
||||
/**
|
||||
* 支付渠道订单号
|
||||
*/
|
||||
private String channelOrderNo;
|
||||
|
||||
/**
|
||||
* 渠道错误码
|
||||
*/
|
||||
private String errCode;
|
||||
|
||||
/**
|
||||
* 渠道错误描述
|
||||
*/
|
||||
private String errMsg;
|
||||
|
||||
/**
|
||||
* 扩展参数,回调时会原样返回
|
||||
*/
|
||||
private String extParam;
|
||||
|
||||
/**
|
||||
* 回调时间,13位时间戳
|
||||
*/
|
||||
private Long notifyTime;
|
||||
|
||||
/**
|
||||
* 签名值
|
||||
*/
|
||||
private String sign;
|
||||
|
||||
/**
|
||||
* 签名类型
|
||||
*/
|
||||
private String signType;
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package com.ruoyi.ai.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* VM卡信息
|
||||
* 当wayCode为BUZHI_VM时,需要在extParam中传入此信息的JSON字符串
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-XX
|
||||
*/
|
||||
@Data
|
||||
public class VmCardInfo {
|
||||
|
||||
/**
|
||||
* 信用卡卡号
|
||||
*/
|
||||
private String number;
|
||||
|
||||
/**
|
||||
* CVC
|
||||
*/
|
||||
private String cvc;
|
||||
|
||||
/**
|
||||
* 过期年(四位数字,如:2027)
|
||||
*/
|
||||
private String expYear;
|
||||
|
||||
/**
|
||||
* 过期月(两位数,如:11)
|
||||
*/
|
||||
private String expMonth;
|
||||
|
||||
/**
|
||||
* 信用卡持有者电子邮件
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 持卡人名字
|
||||
*/
|
||||
private String firstName;
|
||||
|
||||
/**
|
||||
* 持卡人姓氏
|
||||
*/
|
||||
private String lastName;
|
||||
|
||||
/**
|
||||
* 国家: 双字母 ISO 国家代码(两位字母)
|
||||
*/
|
||||
private String country;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.ruoyi.ai.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* VM支付请求
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-XX
|
||||
*/
|
||||
@Data
|
||||
public class VmPayReq {
|
||||
|
||||
/**
|
||||
* 档位ID
|
||||
*/
|
||||
private Long gearId;
|
||||
|
||||
/**
|
||||
* VM卡信息(可选,如果为null则需要在extParam中传入)
|
||||
*/
|
||||
private VmCardInfo vmCardInfo;
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
package com.ruoyi.ai.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* VM统一下单请求
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-XX
|
||||
*/
|
||||
@Data
|
||||
public class VmUnifiedOrderReq {
|
||||
|
||||
/**
|
||||
* 商户号
|
||||
*/
|
||||
private String mchNo;
|
||||
|
||||
/**
|
||||
* 应用ID
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
private String mchOrderNo;
|
||||
|
||||
/**
|
||||
* 支付方式,如:BUZHI_VM(国际VM卡支付)
|
||||
*/
|
||||
private String wayCode;
|
||||
|
||||
/**
|
||||
* 支付金额,单位分
|
||||
*/
|
||||
private Integer amount;
|
||||
|
||||
/**
|
||||
* 货币代码,三位货币代码,人民币:cny 美元:USD
|
||||
*/
|
||||
private String currency;
|
||||
|
||||
/**
|
||||
* 客户端IPV4地址
|
||||
*/
|
||||
private String clientIp;
|
||||
|
||||
/**
|
||||
* 商品标题
|
||||
*/
|
||||
private String subject;
|
||||
|
||||
/**
|
||||
* 商品描述
|
||||
*/
|
||||
private String body;
|
||||
|
||||
/**
|
||||
* 异步通知地址
|
||||
*/
|
||||
private String notifyUrl;
|
||||
|
||||
/**
|
||||
* 订单失效时间,单位秒,默认2小时
|
||||
*/
|
||||
private Integer expiredTime;
|
||||
|
||||
/**
|
||||
* 特定渠道发起的额外参数,json格式字符串
|
||||
*/
|
||||
private String channelExtra;
|
||||
|
||||
/**
|
||||
* 商户扩展参数,回调时会原样返回
|
||||
* 当wayCode为BUZHI_VM时,需要传入VM卡信息的JSON字符串
|
||||
*/
|
||||
private String extParam;
|
||||
|
||||
/**
|
||||
* 请求接口时间,13位时间戳
|
||||
*/
|
||||
private Long reqTime;
|
||||
|
||||
/**
|
||||
* 接口版本号,固定:1.0
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 签名值
|
||||
*/
|
||||
private String sign;
|
||||
|
||||
/**
|
||||
* 签名类型,目前只支持MD5方式
|
||||
*/
|
||||
private String signType;
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package com.ruoyi.ai.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* VM统一下单响应
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-XX
|
||||
*/
|
||||
@Data
|
||||
public class VmUnifiedOrderRes {
|
||||
|
||||
/**
|
||||
* 响应码,0表示成功
|
||||
*/
|
||||
private Integer code;
|
||||
|
||||
/**
|
||||
* 响应消息
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* 响应数据
|
||||
*/
|
||||
private VmUnifiedOrderData data;
|
||||
|
||||
@Data
|
||||
public static class VmUnifiedOrderData {
|
||||
/**
|
||||
* 支付链接
|
||||
*/
|
||||
private String payUrl;
|
||||
|
||||
/**
|
||||
* 订单号
|
||||
*/
|
||||
private String orderId;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
private String mchOrderNo;
|
||||
|
||||
/**
|
||||
* 订单状态
|
||||
*/
|
||||
private Integer orderState;
|
||||
|
||||
/**
|
||||
* 支付参数(某些支付方式可能需要)
|
||||
*/
|
||||
private String payParams;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
package com.ruoyi.ai.service;
|
||||
|
||||
import com.ruoyi.ai.domain.PayResVO;
|
||||
import com.ruoyi.ai.domain.VmCallBackReq;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
|
||||
/**
|
||||
* VM支付服务接口
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-XX
|
||||
*/
|
||||
public interface IVmService {
|
||||
|
||||
/**
|
||||
* VM支付
|
||||
*
|
||||
* @param gearId 档位ID
|
||||
* @param vmCardInfo VM卡信息(可选,如果为null则需要在extParam中传入)
|
||||
* @return 支付结果
|
||||
* @throws Exception 支付异常
|
||||
*/
|
||||
PayResVO vmPay(Long gearId, com.ruoyi.ai.domain.VmCardInfo vmCardInfo) throws Exception;
|
||||
|
||||
/**
|
||||
* VM支付回调
|
||||
*
|
||||
* @param req 回调请求
|
||||
* @return 回调处理结果
|
||||
*/
|
||||
AjaxResult vmCallBack(VmCallBackReq req);
|
||||
}
|
||||
|
|
@ -0,0 +1,368 @@
|
|||
package com.ruoyi.ai.service.impl;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ruoyi.ai.domain.*;
|
||||
import com.ruoyi.ai.service.*;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.AiUser;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.http.OkHttpUtils;
|
||||
import com.ruoyi.common.utils.sign.Md5Utils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* VM支付服务实现
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-XX
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class VmService implements IVmService {
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
|
||||
@Value("${vm.url:http://payment-api.togame.top}")
|
||||
private String url;
|
||||
|
||||
@Value("${vm.mchNo}")
|
||||
private String mchNo;
|
||||
|
||||
@Value("${vm.appId}")
|
||||
private String appId;
|
||||
|
||||
@Value("${vm.secret}")
|
||||
private String secret;
|
||||
|
||||
@Value("${vm.notifyUrl}")
|
||||
private String notifyUrl;
|
||||
|
||||
@Value("${vm.wayCode:BUZHI_VM}")
|
||||
private String wayCode;
|
||||
|
||||
@Value("${vm.currency:USD}")
|
||||
private String currency;
|
||||
|
||||
@Autowired
|
||||
private IAiRechargeService aiRechargeService;
|
||||
|
||||
@Autowired
|
||||
private IAiUserService aiUserService;
|
||||
|
||||
@Autowired
|
||||
private IAiRechargeGiftGearService aiRechargeGiftGearService;
|
||||
|
||||
@Autowired
|
||||
private IAiRechargeGiftService aiRechargeGiftService;
|
||||
|
||||
@Autowired
|
||||
private IExchangeRateService exchangeRateService;
|
||||
|
||||
@Override
|
||||
public PayResVO vmPay(Long gearId, VmCardInfo vmCardInfo) throws Exception {
|
||||
// 充值挡位查询
|
||||
AiRechargeGiftGear aiRechargeGiftGear = aiRechargeGiftGearService.selectAiRechargeGiftGearById(gearId);
|
||||
if (aiRechargeGiftGear == null) {
|
||||
throw new ServiceException("The gear position does not exist.", -1);
|
||||
}
|
||||
|
||||
BigDecimal amount = aiRechargeGiftGear.getRechargeAmount();
|
||||
// 使用汇率服务转换金额(从USD转换为目标货币,默认USD)
|
||||
// 注意:VM支付使用USD作为基础货币
|
||||
if (!"USD".equalsIgnoreCase(currency)) {
|
||||
amount = exchangeRateService.convertAmount(amount, "USD", currency);
|
||||
}
|
||||
|
||||
// 生成订单号
|
||||
String uuid = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8);
|
||||
String dateTime = new SimpleDateFormat("yyyyMMdd").format(new Date());
|
||||
String orderNo = dateTime + "vm" + uuid;
|
||||
|
||||
// 金额转换为分(整数)
|
||||
int amountInCents = amount.multiply(new BigDecimal(100)).intValue();
|
||||
|
||||
// 构建extParam(VM卡信息)
|
||||
String extParam = null;
|
||||
if (vmCardInfo != null) {
|
||||
extParam = objectMapper.writeValueAsString(vmCardInfo);
|
||||
}
|
||||
|
||||
// 构建统一下单请求
|
||||
VmUnifiedOrderReq req = new VmUnifiedOrderReq();
|
||||
req.setMchNo(mchNo);
|
||||
req.setAppId(appId);
|
||||
req.setMchOrderNo(orderNo);
|
||||
req.setWayCode(wayCode);
|
||||
req.setAmount(amountInCents);
|
||||
req.setCurrency(currency.toLowerCase());
|
||||
req.setSubject("游戏充值");
|
||||
req.setBody("游戏充值");
|
||||
req.setNotifyUrl(notifyUrl + "/api/pay/vm-callBack");
|
||||
req.setExpiredTime(7200); // 默认2小时
|
||||
req.setExtParam(extParam);
|
||||
req.setReqTime(System.currentTimeMillis());
|
||||
req.setVersion("1.0");
|
||||
req.setSignType("MD5");
|
||||
|
||||
// 生成签名
|
||||
String sign = generateSign(req);
|
||||
req.setSign(sign);
|
||||
|
||||
// 构建请求体JSON
|
||||
String jsonBody = objectMapper.writeValueAsString(req);
|
||||
log.info("VM支付请求参数: {}", jsonBody);
|
||||
|
||||
// 构建POST请求
|
||||
Request request = new Request.Builder()
|
||||
.url(url + "/api/pay/unifiedOrder")
|
||||
.header("Content-Type", "application/json")
|
||||
.post(RequestBody.create(MediaType.parse("application/json"), jsonBody))
|
||||
.build();
|
||||
|
||||
// 发送请求
|
||||
Response response = OkHttpUtils.newCall(request).execute();
|
||||
ResponseBody body = response.body();
|
||||
|
||||
if (body == null) {
|
||||
log.error("VM支付请求的响应异常");
|
||||
throw new Exception("vm pay response body is null");
|
||||
}
|
||||
|
||||
String responseBody = body.string();
|
||||
log.info("VM支付请求响应: {}", responseBody);
|
||||
|
||||
VmUnifiedOrderRes res = objectMapper.readValue(responseBody, VmUnifiedOrderRes.class);
|
||||
|
||||
// 检查响应code,0表示成功
|
||||
if (res.getCode() == null || res.getCode() != 0) {
|
||||
String msg = res.getMsg();
|
||||
log.error("VM支付请求失败,code: {}, msg: {}", res.getCode(), msg);
|
||||
throw new ServiceException(msg != null ? msg : "支付请求失败", res.getCode() != null ? res.getCode() : -1);
|
||||
}
|
||||
|
||||
// 检查返回的payUrl
|
||||
String payUrl = null;
|
||||
if (res.getData() != null) {
|
||||
payUrl = res.getData().getPayUrl();
|
||||
}
|
||||
if (payUrl == null || payUrl.trim().isEmpty()) {
|
||||
log.error("VM支付返回的payUrl为空,订单号: {}", orderNo);
|
||||
throw new ServiceException("支付返回的支付链接为空", -1);
|
||||
}
|
||||
|
||||
// 创建充值管理
|
||||
AiUser userInfo = aiUserService.getUserInfo(SecurityUtils.getAiUserId());
|
||||
AiRecharge aiRecharge = new AiRecharge();
|
||||
aiRecharge.setOrderNum(orderNo);
|
||||
aiRecharge.setUserId(SecurityUtils.getAiUserId());
|
||||
aiRecharge.setAmount(amount);
|
||||
aiRecharge.setGearId(gearId);
|
||||
aiRecharge.setGearAmount(aiRechargeGiftGear.getRechargeAmount());
|
||||
aiRecharge.setSource(userInfo.getSource());
|
||||
AiRechargeGift aiRechargeGift = aiRechargeGiftService.selectAiRechargeGiftById(aiRechargeGiftGear.getRechargeId());
|
||||
aiRecharge.setPayType(aiRechargeGift.getPayType());
|
||||
aiRecharge.setPayUrl(payUrl);
|
||||
aiRechargeService.insertAiRecharge(aiRecharge);
|
||||
|
||||
PayResVO payResVO = new PayResVO();
|
||||
payResVO.setOrderNo(orderNo);
|
||||
payResVO.setPayUrl(payUrl);
|
||||
return payResVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public AjaxResult vmCallBack(VmCallBackReq req) {
|
||||
log.info("VM支付回调,订单号: {}, 状态: {}", req.getMchOrderNo(), req.getOrderState());
|
||||
|
||||
// 验证签名
|
||||
String sign = generateCallBackSign(req);
|
||||
if (!sign.equals(req.getSign())) {
|
||||
log.error("VM支付回调签名错误,订单号: {}, 期望签名: {}, 实际签名: {}",
|
||||
req.getMchOrderNo(), sign, req.getSign());
|
||||
return AjaxResult.error("签名验证失败");
|
||||
}
|
||||
|
||||
// 处理订单状态
|
||||
// 订单状态:0-订单生成, 1-支付中, 2-支付成功, 3-支付失败, 4-已撤销, 5-已退款, 6-订单关闭
|
||||
Integer orderState = req.getOrderState();
|
||||
if (orderState == null) {
|
||||
log.error("VM支付回调状态为空,订单号: {}", req.getMchOrderNo());
|
||||
return AjaxResult.error("状态为空");
|
||||
}
|
||||
|
||||
if (orderState == 2) {
|
||||
// 支付成功处理
|
||||
log.info("VM支付成功,订单号: {}", req.getMchOrderNo());
|
||||
aiRechargeService.addRecharge(req.getMchOrderNo());
|
||||
return AjaxResult.success();
|
||||
} else if (orderState == 3) {
|
||||
// 支付失败
|
||||
log.warn("VM支付失败,订单号: {}", req.getMchOrderNo());
|
||||
// 这里可以添加失败处理逻辑,比如更新订单状态为失败
|
||||
return AjaxResult.success();
|
||||
} else {
|
||||
// 其他状态(处理中、已撤销、已退款、订单关闭等)
|
||||
log.info("VM支付状态: {}, 订单号: {}", orderState, req.getMchOrderNo());
|
||||
return AjaxResult.success();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成签名(统一下单)
|
||||
* 第一步:将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式拼接成字符串stringA
|
||||
* 第二步:在stringA最后拼接上key[即 StringA +"&key=" + 私钥 ] 得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写
|
||||
*/
|
||||
private String generateSign(VmUnifiedOrderReq req) {
|
||||
TreeMap<String, Object> params = new TreeMap<>();
|
||||
|
||||
// 添加所有非空参数(sign不参与签名)
|
||||
if (req.getMchNo() != null && !req.getMchNo().isEmpty()) {
|
||||
params.put("mchNo", req.getMchNo());
|
||||
}
|
||||
if (req.getAppId() != null && !req.getAppId().isEmpty()) {
|
||||
params.put("appId", req.getAppId());
|
||||
}
|
||||
if (req.getMchOrderNo() != null && !req.getMchOrderNo().isEmpty()) {
|
||||
params.put("mchOrderNo", req.getMchOrderNo());
|
||||
}
|
||||
if (req.getWayCode() != null && !req.getWayCode().isEmpty()) {
|
||||
params.put("wayCode", req.getWayCode());
|
||||
}
|
||||
if (req.getAmount() != null) {
|
||||
params.put("amount", req.getAmount());
|
||||
}
|
||||
if (req.getCurrency() != null && !req.getCurrency().isEmpty()) {
|
||||
params.put("currency", req.getCurrency());
|
||||
}
|
||||
if (req.getClientIp() != null && !req.getClientIp().isEmpty()) {
|
||||
params.put("clientIp", req.getClientIp());
|
||||
}
|
||||
if (req.getSubject() != null && !req.getSubject().isEmpty()) {
|
||||
params.put("subject", req.getSubject());
|
||||
}
|
||||
if (req.getBody() != null && !req.getBody().isEmpty()) {
|
||||
params.put("body", req.getBody());
|
||||
}
|
||||
if (req.getNotifyUrl() != null && !req.getNotifyUrl().isEmpty()) {
|
||||
params.put("notifyUrl", req.getNotifyUrl());
|
||||
}
|
||||
if (req.getExpiredTime() != null) {
|
||||
params.put("expiredTime", req.getExpiredTime());
|
||||
}
|
||||
if (req.getChannelExtra() != null && !req.getChannelExtra().isEmpty()) {
|
||||
params.put("channelExtra", req.getChannelExtra());
|
||||
}
|
||||
if (req.getExtParam() != null && !req.getExtParam().isEmpty()) {
|
||||
params.put("extParam", req.getExtParam());
|
||||
}
|
||||
if (req.getReqTime() != null) {
|
||||
params.put("reqTime", req.getReqTime());
|
||||
}
|
||||
if (req.getVersion() != null && !req.getVersion().isEmpty()) {
|
||||
params.put("version", req.getVersion());
|
||||
}
|
||||
if (req.getSignType() != null && !req.getSignType().isEmpty()) {
|
||||
params.put("signType", req.getSignType());
|
||||
}
|
||||
|
||||
// 拼接参数
|
||||
StringBuilder stringA = new StringBuilder();
|
||||
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
||||
if (stringA.length() > 0) {
|
||||
stringA.append("&");
|
||||
}
|
||||
stringA.append(entry.getKey()).append("=").append(entry.getValue());
|
||||
}
|
||||
|
||||
// 拼接key
|
||||
String stringSignTemp = stringA.toString() + "&key=" + secret;
|
||||
log.debug("VM签名源字符串: {}", stringSignTemp);
|
||||
|
||||
// MD5并转大写
|
||||
String sign = Md5Utils.hash(stringSignTemp).toUpperCase();
|
||||
return sign;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成回调签名
|
||||
*/
|
||||
private String generateCallBackSign(VmCallBackReq req) {
|
||||
TreeMap<String, Object> params = new TreeMap<>();
|
||||
|
||||
// 添加所有非空参数(sign不参与签名)
|
||||
if (req.getMchNo() != null && !req.getMchNo().isEmpty()) {
|
||||
params.put("mchNo", req.getMchNo());
|
||||
}
|
||||
if (req.getAppId() != null && !req.getAppId().isEmpty()) {
|
||||
params.put("appId", req.getAppId());
|
||||
}
|
||||
if (req.getMchOrderNo() != null && !req.getMchOrderNo().isEmpty()) {
|
||||
params.put("mchOrderNo", req.getMchOrderNo());
|
||||
}
|
||||
if (req.getPayOrderId() != null && !req.getPayOrderId().isEmpty()) {
|
||||
params.put("payOrderId", req.getPayOrderId());
|
||||
}
|
||||
if (req.getWayCode() != null && !req.getWayCode().isEmpty()) {
|
||||
params.put("wayCode", req.getWayCode());
|
||||
}
|
||||
if (req.getAmount() != null) {
|
||||
params.put("amount", req.getAmount());
|
||||
}
|
||||
if (req.getCurrency() != null && !req.getCurrency().isEmpty()) {
|
||||
params.put("currency", req.getCurrency());
|
||||
}
|
||||
if (req.getOrderState() != null) {
|
||||
params.put("orderState", req.getOrderState());
|
||||
}
|
||||
if (req.getChannelOrderNo() != null && !req.getChannelOrderNo().isEmpty()) {
|
||||
params.put("channelOrderNo", req.getChannelOrderNo());
|
||||
}
|
||||
if (req.getErrCode() != null && !req.getErrCode().isEmpty()) {
|
||||
params.put("errCode", req.getErrCode());
|
||||
}
|
||||
if (req.getErrMsg() != null && !req.getErrMsg().isEmpty()) {
|
||||
params.put("errMsg", req.getErrMsg());
|
||||
}
|
||||
if (req.getExtParam() != null && !req.getExtParam().isEmpty()) {
|
||||
params.put("extParam", req.getExtParam());
|
||||
}
|
||||
if (req.getNotifyTime() != null) {
|
||||
params.put("notifyTime", req.getNotifyTime());
|
||||
}
|
||||
if (req.getSignType() != null && !req.getSignType().isEmpty()) {
|
||||
params.put("signType", req.getSignType());
|
||||
}
|
||||
|
||||
// 拼接参数
|
||||
StringBuilder stringA = new StringBuilder();
|
||||
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
||||
if (stringA.length() > 0) {
|
||||
stringA.append("&");
|
||||
}
|
||||
stringA.append(entry.getKey()).append("=").append(entry.getValue());
|
||||
}
|
||||
|
||||
// 拼接key
|
||||
String stringSignTemp = stringA.toString() + "&key=" + secret;
|
||||
log.debug("VM回调签名源字符串: {}", stringSignTemp);
|
||||
|
||||
// MD5并转大写
|
||||
String sign = Md5Utils.hash(stringSignTemp).toUpperCase();
|
||||
return sign;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue