diff --git a/ruoyi-admin/src/main/java/com/ruoyi/api/PayController.java b/ruoyi-admin/src/main/java/com/ruoyi/api/PayController.java index 431e5fb..871c77a 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/api/PayController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/api/PayController.java @@ -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); } diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index b369ff8..1268461 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -71,6 +71,12 @@ commons-io + + + commons-codec + commons-codec + + org.apache.poi diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/RSAUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/RSAUtils.java index 8229dd7..02170be 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/RSAUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/RSAUtils.java @@ -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 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 encry pting string [" + data + "]", 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 whil e decrypting the string[" + data + "]", 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; } @@ -179,7 +220,7 @@ public class RSAUtils { offSet = i * maxBlock; } } catch (Exception e) { - throw new RuntimeException("An exception occurred when encryp ting and decrypting data whose threshold is [" + maxBlock + "]", e); + throw new RuntimeException("An exception occurred when encrypting and decrypting data whose threshold is [" + maxBlock + "]", e); } byte[] resultDatas = out.toByteArray(); IOUtils.closeQuietly(out); diff --git a/ruoyi-system/src/main/java/com/ruoyi/ai/domain/AiTemplate.java b/ruoyi-system/src/main/java/com/ruoyi/ai/domain/AiTemplate.java index 08611e0..6b74db8 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/ai/domain/AiTemplate.java +++ b/ruoyi-system/src/main/java/com/ruoyi/ai/domain/AiTemplate.java @@ -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; diff --git a/ruoyi-system/src/main/java/com/ruoyi/ai/service/IJinShaService.java b/ruoyi-system/src/main/java/com/ruoyi/ai/service/IJinShaService.java index 20a975a..e995765 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/ai/service/IJinShaService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/ai/service/IJinShaService.java @@ -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; /** diff --git a/ruoyi-system/src/main/java/com/ruoyi/ai/service/impl/JinShaService.java b/ruoyi-system/src/main/java/com/ruoyi/ai/service/impl/JinShaService.java index 205ed50..0612fac 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/ai/service/impl/JinShaService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/ai/service/impl/JinShaService.java @@ -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 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; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/ai/service/impl/YuZhouService.java b/ruoyi-system/src/main/java/com/ruoyi/ai/service/impl/YuZhouService.java index b12b677..40edd36 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/ai/service/impl/YuZhouService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/ai/service/impl/YuZhouService.java @@ -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 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 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 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"; } - //充值成功处理 - aiRechargeService.addRecharge(orderNo); - return "SUCCESS"; } diff --git a/ruoyi-system/src/main/resources/mapper/system/AiTemplateMapper.xml b/ruoyi-system/src/main/resources/mapper/system/AiTemplateMapper.xml index afb0aa7..9ca60f9 100644 --- a/ruoyi-system/src/main/resources/mapper/system/AiTemplateMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/AiTemplateMapper.xml @@ -10,6 +10,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + @@ -20,7 +21,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - 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 @@ -46,6 +48,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" chinese_content, english_content, image_url, + ai_id, status, remark, create_time, @@ -59,6 +62,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{chineseContent}, #{englishContent}, #{imageUrl}, + #{aiId}, #{status}, #{remark}, #{createTime}, @@ -76,6 +80,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" chinese_content = #{chineseContent}, english_content = #{englishContent}, image_url = #{imageUrl}, + ai_id = #{aiId}, status = #{status}, remark = #{remark}, create_time = #{createTime}, diff --git a/sql/aisql.sql b/sql/aisql.sql index 8025d5f..f86ed1a 100644 --- a/sql/aisql.sql +++ b/sql/aisql.sql @@ -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;