fix: yuzhou支付重新对接
This commit is contained in:
parent
95db7f9e30
commit
6701b8f765
|
|
@ -31,8 +31,8 @@ public class PayController {
|
|||
*/
|
||||
@GetMapping("/jinsha-pay")
|
||||
@ApiOperation("jinsha请求支付")
|
||||
public AjaxResult jinShaPay(Long gearId, String cardno, String cardname) throws Exception {
|
||||
PayResVO payResVO = jinShaService.jinShaPay(gearId, cardno, cardname);
|
||||
public AjaxResult jinShaPay(Long gearId) throws Exception {
|
||||
PayResVO payResVO = jinShaService.jinShaPay(gearId);
|
||||
return AjaxResult.success(payResVO);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,12 @@
|
|||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache Commons Codec for Base64 encoding/decoding -->
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- excel工具 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
package com.ruoyi.common.utils.sign;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -16,25 +21,29 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
public class RSAUtils {
|
||||
|
||||
// RSA最⼤加密明⽂⼤⼩
|
||||
// RSA最大加密明文大小
|
||||
private static final int MAX_ENCRYPT_BLOCK = 117;
|
||||
// 不仅可以使⽤DSA算法,同样也可以使⽤RSA算法做数字签名
|
||||
// 不仅可以使用DSA算法,同样也可以使用RSA算法做数字签名
|
||||
private static final String KEY_ALGORITHM = "RSA";
|
||||
|
||||
public static String encryptByPrivateKey(String str, String privateKey) throws Exception {
|
||||
public static String encryptByPrivateKey(String str, String privateKey)
|
||||
throws InvalidKeySpecException, NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException, java.security.InvalidKeyException,
|
||||
javax.crypto.IllegalBlockSizeException, javax.crypto.BadPaddingException, UnsupportedEncodingException {
|
||||
// base64编码的公钥
|
||||
byte[] keyBytes = decryptBASE64(privateKey);
|
||||
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(KEY_ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
|
||||
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(KEY_ALGORITHM)
|
||||
.generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
|
||||
// RSA加密
|
||||
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, priKey);
|
||||
byte[] data = str.getBytes("UTF-8");
|
||||
// 加密时超过117字节就报错。为此采⽤分段加密的办法来加密
|
||||
// 加密时超过117字节就报错。为此采用分段加密的办法来加密
|
||||
byte[] enBytes = null;
|
||||
for (int i = 0; i < data.length; i += MAX_ENCRYPT_BLOCK) {
|
||||
// 注意要使⽤2的倍数,否则会出现加密后的内容再解密时为乱码
|
||||
// 注意要使用2的倍数,否则会出现加密后的内容再解密时为乱码
|
||||
byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_ENCRYPT_BLOCK));
|
||||
enBytes = ArrayUtils.addAll(enBytes, doFinal);
|
||||
}
|
||||
|
|
@ -43,15 +52,22 @@ public class RSAUtils {
|
|||
}
|
||||
|
||||
private static String encryptBASE64(byte[] data) {
|
||||
return new String(Base64.encode(data));
|
||||
return new String(Base64.encodeBase64(data));
|
||||
}
|
||||
|
||||
private static byte[] decryptBASE64(String data) {
|
||||
return Base64.decode(data);
|
||||
return Base64.decodeBase64(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify signature
|
||||
*
|
||||
* @param params
|
||||
* @return
|
||||
*/
|
||||
public static boolean verifySign(JSONObject params, String publickey) {
|
||||
String platSign = params.getStr("signature"); // sign
|
||||
log.info("signature:" + platSign);
|
||||
List<String> paramNameList = new ArrayList<>();
|
||||
for (String key : params.keySet()) {
|
||||
if (!"signature".equals(key)) {
|
||||
|
|
@ -64,13 +80,14 @@ public class RSAUtils {
|
|||
String name = paramNameList.get(i);
|
||||
stringBuilder.append(params.getStr(name));
|
||||
}
|
||||
log.info("keys:" + stringBuilder);
|
||||
String decryptSign = "";
|
||||
try {
|
||||
decryptSign = publicDecrypt(platSign, getPublicKey(publickey)
|
||||
);
|
||||
decryptSign = publicDecrypt(platSign, getPublicKey(publickey));
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.toString());
|
||||
log.error("Error decrypting signature", e);
|
||||
}
|
||||
log.info("decryptSign:" + decryptSign);
|
||||
if (!stringBuilder.toString().equalsIgnoreCase(decryptSign)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -89,11 +106,12 @@ public class RSAUtils {
|
|||
stringBuilder.append(createMap.get(key)); // 拼接参数
|
||||
}
|
||||
String keyStr = stringBuilder.toString(); // 得到待加密的字符串
|
||||
log.info("keyStr:" + keyStr);
|
||||
String signedStr = "";
|
||||
try {
|
||||
signedStr = privateEncrypt(keyStr, getPrivateKey(MCH_PRIVATE_KEY)); // 私钥加密
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.toString());
|
||||
log.error("Error encrypting signature", e);
|
||||
}
|
||||
return signedStr;
|
||||
}
|
||||
|
|
@ -110,47 +128,70 @@ public class RSAUtils {
|
|||
stringBuilder.append(createMap.get(key)); // 拼接参数
|
||||
}
|
||||
String keyStr = stringBuilder.toString(); // 得到待加密的字符串
|
||||
log.info("keyStr:" + keyStr);
|
||||
String signedStr = "";
|
||||
try {
|
||||
signedStr = privateEncrypt(keyStr, getPrivateKey(MCH_PRIVATE_KEY)); // 私钥加密
|
||||
} catch (Exception e) {
|
||||
System.out.println(e.toString());
|
||||
log.error("Error encrypting signature", e);
|
||||
}
|
||||
return signedStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* private key encryption
|
||||
*
|
||||
* @param data
|
||||
* @param privateKey
|
||||
* @return
|
||||
*/
|
||||
public static String privateEncrypt(String data, RSAPrivateKey privateKey) {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
|
||||
return Base64.encode(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes("UTF-8"), privateKey.getModulus().bitLength()));
|
||||
return Base64.encodeBase64String(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes("UTF-8"), privateKey.getModulus().bitLength()));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Exception encountered while encrypting string [" + data + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* public key decryption
|
||||
*/
|
||||
public static String publicDecrypt(String data, RSAPublicKey publicKey) {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("RSA");
|
||||
cipher.init(Cipher.DECRYPT_MODE, publicKey);
|
||||
return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decode(data), publicKey.getModulus().bitLength()), "UTF-8");
|
||||
return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), "UTF-8");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("An exception was encountered while decrypting the string[" + data + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static RSAPrivateKey getPrivateKey(String privateKey) throws Exception {
|
||||
/**
|
||||
* get private key
|
||||
*
|
||||
* @param privateKey key string (base64 encoded)
|
||||
* @throws Exception
|
||||
*/
|
||||
public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
//Get the private key object through the PKCS#8 encoded Key instruction
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKey));
|
||||
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
|
||||
RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
|
||||
return key;
|
||||
}
|
||||
|
||||
public static RSAPublicKey getPublicKey(String publicKey) throws Exception {
|
||||
/**
|
||||
* get the public key
|
||||
*
|
||||
* @param publicKey key string (base64 encoded)
|
||||
* @throws Exception
|
||||
*/
|
||||
public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
//Get the public key object through the X509 encoded Key instruction
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decode(publicKey));
|
||||
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
|
||||
RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
|
||||
return key;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ public class AiTemplate extends BaseEntity {
|
|||
@Excel(name = "模版图片URL")
|
||||
private String imageUrl;
|
||||
|
||||
/** AI类型 */
|
||||
@Excel(name = "AI类型")
|
||||
private Long aiId;
|
||||
|
||||
/** 状态:0-禁用,1-启用 */
|
||||
@Excel(name = "状态:0-禁用,1-启用")
|
||||
private Integer status;
|
||||
|
|
|
|||
|
|
@ -9,10 +9,8 @@ public interface IJinShaService {
|
|||
/**
|
||||
* 支付
|
||||
* @param gearId 档位ID
|
||||
* @param cardno 银行卡号
|
||||
* @param cardname 银行卡姓名
|
||||
*/
|
||||
PayResVO jinShaPay(Long gearId, String cardno, String cardname) throws Exception;
|
||||
PayResVO jinShaPay(Long gearId) throws Exception;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -53,15 +53,7 @@ public class JinShaService implements IJinShaService {
|
|||
private IExchangeRateService exchangeRateService;
|
||||
|
||||
@Override
|
||||
public PayResVO jinShaPay(Long gearId, String cardno, String cardname) throws Exception {
|
||||
|
||||
// 验证参数
|
||||
if (cardno == null || cardno.trim().isEmpty()) {
|
||||
throw new ServiceException("银行卡号不能为空", -1);
|
||||
}
|
||||
if (cardname == null || cardname.trim().isEmpty()) {
|
||||
throw new ServiceException("银行卡姓名不能为空", -1);
|
||||
}
|
||||
public PayResVO jinShaPay(Long gearId) throws Exception {
|
||||
|
||||
//充值挡位查询
|
||||
AiRechargeGiftGear aiRechargeGiftGear = aiRechargeGiftGearService.selectAiRechargeGiftGearById(gearId);
|
||||
|
|
@ -77,16 +69,20 @@ public class JinShaService implements IJinShaService {
|
|||
String dateTime = new SimpleDateFormat("yyyyMMdd").format(new Date());
|
||||
String orderNo = dateTime + "js" + uuid;
|
||||
|
||||
// 金额转换为int类型(去除小数部分)
|
||||
int amountInt = amount.intValue();
|
||||
// 金额转换为number类型(保留两位小数)
|
||||
String amountStr = String.format("%.2f", amount.doubleValue());
|
||||
|
||||
// 1. 配置签名参数(按照key排序,不包含notify_url和sign)
|
||||
// 构建回调地址和返回地址
|
||||
String notifyUrlFull = notifyUrl + "/api/pay/jinsha-callBack";
|
||||
String returnUrlFull = returnUrl + "/recharge";
|
||||
|
||||
// 1. 配置签名参数(按照key排序:appid, amount, orderno, notify_url, return_url,不包含sign)
|
||||
TreeMap<String, Object> signParams = new TreeMap<>();
|
||||
signParams.put("appid", appId);
|
||||
signParams.put("amount", amountInt);
|
||||
signParams.put("amount", amountStr);
|
||||
signParams.put("orderno", orderNo);
|
||||
signParams.put("cardno", cardno);
|
||||
signParams.put("cardname", cardname);
|
||||
signParams.put("notify_url", notifyUrlFull);
|
||||
signParams.put("return_url", returnUrlFull);
|
||||
|
||||
// 2. 生成签名
|
||||
String sign = this.generateSign(signParams);
|
||||
|
|
@ -94,20 +90,21 @@ public class JinShaService implements IJinShaService {
|
|||
// 3. 构建请求参数(使用FormBody.Builder自动处理URL编码)
|
||||
FormBody.Builder formBuilder = new FormBody.Builder();
|
||||
formBuilder.add("appid", appId);
|
||||
formBuilder.add("amount", String.valueOf(amountInt));
|
||||
formBuilder.add("amount", amountStr);
|
||||
formBuilder.add("orderno", orderNo);
|
||||
formBuilder.add("cardno", cardno);
|
||||
formBuilder.add("cardname", cardname);
|
||||
formBuilder.add("notify_url", notifyUrl + "/api/pay/jinsha-callBack");
|
||||
formBuilder.add("notify_url", notifyUrlFull);
|
||||
formBuilder.add("return_url", returnUrlFull);
|
||||
formBuilder.add("sign", sign);
|
||||
RequestBody requestBody = formBuilder.build();
|
||||
// 5. 构建 POST 请求
|
||||
|
||||
// 4. 构建 POST 请求
|
||||
Request request = new Request.Builder()
|
||||
.url(url + "/api/pay")
|
||||
.header("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
|
||||
.post(requestBody)
|
||||
.build();
|
||||
// 6. 发送请求并获取响应
|
||||
|
||||
// 5. 发送请求并获取响应
|
||||
Response response = OkHttpUtils.newCall(request).execute();
|
||||
ResponseBody body = response.body();
|
||||
if (null == body) {
|
||||
|
|
@ -126,6 +123,16 @@ public class JinShaService implements IJinShaService {
|
|||
throw new ServiceException(msg != null ? msg : "支付请求失败", code != null ? code : -1);
|
||||
}
|
||||
|
||||
// 检查返回的payurl
|
||||
String payUrl = null;
|
||||
if (jinShaBodyRes.getData() != null) {
|
||||
payUrl = jinShaBodyRes.getData().getPayurl();
|
||||
}
|
||||
if (payUrl == null || payUrl.trim().isEmpty()) {
|
||||
log.error("jinsha支付返回的payurl为空,订单号: {}", orderNo);
|
||||
throw new ServiceException("支付返回的支付链接为空", -1);
|
||||
}
|
||||
|
||||
// 创建充值管理
|
||||
AiUser userInfo = aiUserService.getUserInfo(SecurityUtils.getAiUserId());
|
||||
AiRecharge aiRecharge = new AiRecharge();
|
||||
|
|
@ -137,12 +144,12 @@ public class JinShaService implements IJinShaService {
|
|||
aiRecharge.setSource(userInfo.getSource());
|
||||
AiRechargeGift aiRechargeGift = aiRechargeGiftService.selectAiRechargeGiftById(aiRechargeGiftGear.getRechargeId());
|
||||
aiRecharge.setPayType(aiRechargeGift.getPayType());
|
||||
// jinsha支付成功返回后,不需要支付URL,订单状态由回调更新
|
||||
aiRecharge.setPayUrl(payUrl);
|
||||
aiRechargeService.insertAiRecharge(aiRecharge);
|
||||
|
||||
PayResVO payResVO = new PayResVO();
|
||||
payResVO.setOrderNo(orderNo);
|
||||
// jinsha支付成功后不需要跳转支付页面,直接返回订单号
|
||||
payResVO.setPayUrl(payUrl);
|
||||
return payResVO;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,37 +60,111 @@ public class YuZhouService implements IYuZhouService {
|
|||
String dateTime = new SimpleDateFormat("yyyyMMdd").format(new Date());
|
||||
String orderNo = dateTime + "yz" + uuid;
|
||||
|
||||
// 获取用户信息
|
||||
AiUser userInfo = aiUserService.getUserInfo(SecurityUtils.getAiUserId());
|
||||
|
||||
// 处理用户姓名,如果没有则使用默认值
|
||||
String firstName = "John";
|
||||
String lastName = "Doe";
|
||||
if (userInfo.getNickname() != null && !userInfo.getNickname().trim().isEmpty()) {
|
||||
String[] nameParts = userInfo.getNickname().trim().split("\\s+");
|
||||
if (nameParts.length >= 2) {
|
||||
firstName = nameParts[0];
|
||||
lastName = nameParts[nameParts.length - 1];
|
||||
} else if (nameParts.length == 1) {
|
||||
firstName = nameParts[0];
|
||||
}
|
||||
}
|
||||
|
||||
// 从用户表获取邮箱
|
||||
String email = userInfo.getEmail();
|
||||
if (email == null || email.trim().isEmpty()) {
|
||||
log.warn("用户邮箱为空 userId: {}, nickname: {}", userInfo.getId(), userInfo.getNickname());
|
||||
// 如果用户邮箱为空,使用默认邮箱格式
|
||||
email = "user" + userInfo.getId() + "@example.com";
|
||||
} else {
|
||||
email = email.trim();
|
||||
}
|
||||
|
||||
// 处理电话,如果没有则使用默认值
|
||||
String phone = userInfo.getPhone();
|
||||
if (phone == null || phone.trim().isEmpty()) {
|
||||
phone = "1234567890";
|
||||
} else {
|
||||
// 确保电话是10位数字
|
||||
phone = phone.replaceAll("[^0-9]", "");
|
||||
if (phone.length() < 10) {
|
||||
// 如果不足10位,用0补齐
|
||||
phone = String.format("%010d", phone.length() > 0 ? Long.parseLong(phone) : 0);
|
||||
} else if (phone.length() > 10) {
|
||||
// 如果超过10位,取后10位
|
||||
phone = phone.substring(phone.length() - 10);
|
||||
}
|
||||
}
|
||||
|
||||
// 构建请求参数
|
||||
Map<String, Object> createMap = new HashMap<>();
|
||||
createMap.put("merchantNo", appId);
|
||||
createMap.put("orderNo", orderNo);
|
||||
createMap.put("money", amount.toString());
|
||||
createMap.put("description", "test");
|
||||
createMap.put("name", "test");
|
||||
createMap.put("email", "test@gmail.com");
|
||||
createMap.put("callbackUrl", callbackUrl + "/api/pay/yuzhou-callBack");
|
||||
createMap.put("phone", "7383442114");
|
||||
createMap.put("description", "Recharge");
|
||||
createMap.put("email", email);
|
||||
createMap.put("phone", phone);
|
||||
createMap.put("notifyUrl", callbackUrl + "/api/pay/yuzhou-callBack");
|
||||
createMap.put("expiredPeriod", "1440");
|
||||
createMap.put("redirectUrl", redirectUrl + "/recharge");
|
||||
createMap.put("currency", "USD");
|
||||
createMap.put("firstName", firstName);
|
||||
createMap.put("lastName", lastName);
|
||||
createMap.put("street", "123 Main Street");
|
||||
createMap.put("city", "New York");
|
||||
createMap.put("state", "NY");
|
||||
createMap.put("country", userInfo.getCountry() != null && !userInfo.getCountry().trim().isEmpty() ? userInfo.getCountry() : "US");
|
||||
createMap.put("postcode", "10001");
|
||||
|
||||
// 生成签名(注意:签名时不包括signature字段)
|
||||
String signedStr = RSAUtils.getSignStr(createMap, secretKey);
|
||||
createMap.put("signature", signedStr);
|
||||
|
||||
String postStr = JSONUtil.toJsonStr(createMap);
|
||||
String response = HttpRequest.post(url + "/gateway/order/US/payIn").header("Content-Type", "application/json")
|
||||
.body(postStr).execute().body();
|
||||
log.info("yuzhou支付请求参数: {}", postStr);
|
||||
|
||||
// 调用新的接口地址
|
||||
String response = HttpRequest.post(url + "/gateway/US/payIn")
|
||||
.header("Content-Type", "application/json; charset=utf-8")
|
||||
.body(postStr)
|
||||
.execute()
|
||||
.body();
|
||||
|
||||
log.info("yuzhou支付响应: {}", response);
|
||||
|
||||
JSONObject returnObj = JSONUtil.parseObj(response);
|
||||
Integer code = returnObj.getInt("code");
|
||||
if (200 != code) {
|
||||
log.error("yuzhou支付请求的响应异常 {}", returnObj);
|
||||
throw new Exception("yuzhoupay responsebody is null");
|
||||
String msg = returnObj.getStr("msg");
|
||||
log.error("yuzhou支付请求的响应异常 code: {}, msg: {}, response: {}", code, msg, returnObj);
|
||||
throw new ServiceException("yuzhoupay request failed: " + (msg != null ? msg : "unknown error"), code);
|
||||
}
|
||||
|
||||
JSONObject data = returnObj.getJSONObject("data");
|
||||
if (data == null) {
|
||||
log.error("yuzhou支付响应数据为空: {}", returnObj);
|
||||
throw new ServiceException("yuzhoupay response data is null", -1);
|
||||
}
|
||||
|
||||
String money = data.getStr("money");
|
||||
String payUrl = data.getStr("url");
|
||||
String platformOrderNo = data.getStr("platformOrderNo");
|
||||
|
||||
if (payUrl == null || payUrl.trim().isEmpty()) {
|
||||
log.error("yuzhou支付URL为空: {}", data);
|
||||
throw new ServiceException("yuzhoupay url is null", -1);
|
||||
}
|
||||
|
||||
// 创建充值管理
|
||||
AiUser userInfo = aiUserService.getUserInfo(SecurityUtils.getAiUserId());
|
||||
AiRecharge aiRecharge = new AiRecharge();
|
||||
aiRecharge.setOrderNum(orderNo);
|
||||
aiRecharge.setUserId(SecurityUtils.getAiUserId());
|
||||
aiRecharge.setAmount(new BigDecimal(money));
|
||||
aiRecharge.setAmount(new BigDecimal(money != null ? money : amount.toString()));
|
||||
aiRecharge.setGearId(gearId);
|
||||
aiRecharge.setSource(userInfo.getSource());
|
||||
aiRecharge.setGearAmount(aiRechargeGiftGear.getRechargeAmount());
|
||||
|
|
@ -98,6 +172,7 @@ public class YuZhouService implements IYuZhouService {
|
|||
aiRecharge.setPayType(aiRechargeGift.getPayType());
|
||||
aiRecharge.setPayUrl(payUrl);
|
||||
aiRechargeService.insertAiRecharge(aiRecharge);
|
||||
|
||||
PayResVO payResVO = new PayResVO();
|
||||
payResVO.setOrderNo(orderNo);
|
||||
payResVO.setPayUrl(payUrl);
|
||||
|
|
@ -106,31 +181,60 @@ public class YuZhouService implements IYuZhouService {
|
|||
|
||||
@Override
|
||||
public String callBack(Map<String, Object> map) throws Exception {
|
||||
int code = Integer.parseInt(map.get("status").toString());
|
||||
String orderNo = map.get("orderNo").toString();
|
||||
if (10 != code) {
|
||||
log.error("yuzhou支付失败 {}", orderNo);
|
||||
return null;
|
||||
log.info("yuzhou支付回调接收参数: {}", map);
|
||||
|
||||
// 验证必要参数
|
||||
if (map == null || map.isEmpty()) {
|
||||
log.error("yuzhou支付回调参数为空");
|
||||
return "FAIL";
|
||||
}
|
||||
// Map<String, Object> createMap = new HashMap<>();
|
||||
// createMap.put("orderNo", orderNo);
|
||||
// createMap.put("platOrderNo", map.get("platOrderNo"));
|
||||
// createMap.put("money", map.get("money"));
|
||||
// createMap.put("fee", map.get("fee"));
|
||||
// createMap.put("status", map.get("status"));
|
||||
// createMap.put("message", map.get("message"));
|
||||
String signature = map.get("signature").toString();
|
||||
|
||||
Object statusObj = map.get("status");
|
||||
Object orderNoObj = map.get("orderNo");
|
||||
|
||||
if (statusObj == null || orderNoObj == null) {
|
||||
log.error("yuzhou支付回调缺少必要参数: status={}, orderNo={}", statusObj, orderNoObj);
|
||||
return "FAIL";
|
||||
}
|
||||
|
||||
int status = Integer.parseInt(statusObj.toString());
|
||||
String orderNo = orderNoObj.toString();
|
||||
|
||||
log.info("yuzhou支付回调 orderNo: {}, status: {}", orderNo, status);
|
||||
|
||||
// 验证签名
|
||||
Object signatureObj = map.get("signature");
|
||||
if (signatureObj == null) {
|
||||
log.error("yuzhou支付回调缺少签名参数 orderNo: {}", orderNo);
|
||||
return "FAIL";
|
||||
}
|
||||
|
||||
JSONObject entries = JSONUtil.parseObj(map);
|
||||
boolean b = RSAUtils.verifySign(entries, publicKey);
|
||||
if (!b) {
|
||||
log.error("yuzhou支付回调签名错误 {}", orderNo);
|
||||
log.error("yuzhou支付回调签名 {}", signature);
|
||||
log.error("yuzhou支付回调报文 {}", map);
|
||||
return null;
|
||||
boolean verifyResult = RSAUtils.verifySign(entries, publicKey);
|
||||
if (!verifyResult) {
|
||||
log.error("yuzhou支付回调签名验证失败 orderNo: {}", orderNo);
|
||||
log.error("yuzhou支付回调签名: {}", signatureObj);
|
||||
log.error("yuzhou支付回调完整报文: {}", map);
|
||||
return "FAIL";
|
||||
}
|
||||
|
||||
log.info("yuzhou支付回调签名验证成功 orderNo: {}", orderNo);
|
||||
|
||||
// 判断订单状态,10表示成功
|
||||
if (10 != status) {
|
||||
log.warn("yuzhou支付订单状态非成功 orderNo: {}, status: {}", orderNo, status);
|
||||
return "SUCCESS"; // 即使失败也返回SUCCESS,避免重复回调
|
||||
}
|
||||
|
||||
// 充值成功处理
|
||||
try {
|
||||
aiRechargeService.addRecharge(orderNo);
|
||||
log.info("yuzhou支付回调处理成功 orderNo: {}", orderNo);
|
||||
return "SUCCESS";
|
||||
} catch (Exception e) {
|
||||
log.error("yuzhou支付回调处理失败 orderNo: {}", orderNo, e);
|
||||
return "FAIL";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<result property="chineseContent" column="chinese_content" />
|
||||
<result property="englishContent" column="english_content" />
|
||||
<result property="imageUrl" column="image_url" />
|
||||
<result property="aiId" column="ai_id" />
|
||||
<result property="status" column="status" />
|
||||
<result property="remark" column="remark" />
|
||||
<result property="createTime" column="create_time" />
|
||||
|
|
@ -20,7 +21,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
</resultMap>
|
||||
|
||||
<sql id="selectAiTemplateVo">
|
||||
select id, name, chinese_content, english_content, image_url, status, remark, create_time, create_by, update_by, update_time, del_flag from ai_template
|
||||
select id, name, chinese_content, english_content, image_url, ai_id, status, remark, create_time, create_by, update_by, update_time, del_flag from ai_template
|
||||
</sql>
|
||||
|
||||
<select id="selectAiTemplateList" parameterType="AiTemplate" resultMap="AiTemplateResult">
|
||||
|
|
@ -30,6 +31,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<if test="chineseContent != null and chineseContent != ''"> and chinese_content = #{chineseContent}</if>
|
||||
<if test="englishContent != null and englishContent != ''"> and english_content = #{englishContent}</if>
|
||||
<if test="imageUrl != null and imageUrl != ''"> and image_url = #{imageUrl}</if>
|
||||
<if test="aiId != null and aiId != ''"> and ai_id = #{aiId}</if>
|
||||
<if test="status != null "> and status = #{status}</if>
|
||||
</where>
|
||||
</select>
|
||||
|
|
@ -46,6 +48,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<if test="chineseContent != null">chinese_content,</if>
|
||||
<if test="englishContent != null">english_content,</if>
|
||||
<if test="imageUrl != null">image_url,</if>
|
||||
<if test="aiId != null">ai_id,</if>
|
||||
<if test="status != null">status,</if>
|
||||
<if test="remark != null">remark,</if>
|
||||
<if test="createTime != null">create_time,</if>
|
||||
|
|
@ -59,6 +62,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<if test="chineseContent != null">#{chineseContent},</if>
|
||||
<if test="englishContent != null">#{englishContent},</if>
|
||||
<if test="imageUrl != null">#{imageUrl},</if>
|
||||
<if test="aiId != null">#{aiId},</if>
|
||||
<if test="status != null">#{status},</if>
|
||||
<if test="remark != null">#{remark},</if>
|
||||
<if test="createTime != null">#{createTime},</if>
|
||||
|
|
@ -76,6 +80,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<if test="chineseContent != null">chinese_content = #{chineseContent},</if>
|
||||
<if test="englishContent != null">english_content = #{englishContent},</if>
|
||||
<if test="imageUrl != null">image_url = #{imageUrl},</if>
|
||||
<if test="aiId != null">ai_id = #{aiId},</if>
|
||||
<if test="status != null">status = #{status},</if>
|
||||
<if test="remark != null">remark = #{remark},</if>
|
||||
<if test="createTime != null">create_time = #{createTime},</if>
|
||||
|
|
|
|||
|
|
@ -2866,7 +2866,7 @@ CREATE TABLE `ai_recharge` (
|
|||
`gift_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '到账金额',
|
||||
`give_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '赠送金额',
|
||||
`pay_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支付方式',
|
||||
`pay_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支付链接',
|
||||
`pay_url` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支付链接',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 118 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '充值记录' ROW_FORMAT = DYNAMIC;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue