fix: jinsha支付重新对接

This commit is contained in:
old burden 2026-01-21 11:42:34 +08:00
parent 44ae69e31f
commit 95db7f9e30
4 changed files with 120 additions and 39 deletions

View File

@ -31,8 +31,8 @@ public class PayController {
*/
@GetMapping("/jinsha-pay")
@ApiOperation("jinsha请求支付")
public AjaxResult jinShaPay(Long gearId) throws Exception {
PayResVO payResVO = jinShaService.jinShaPay(gearId);
public AjaxResult jinShaPay(Long gearId, String cardno, String cardname) throws Exception {
PayResVO payResVO = jinShaService.jinShaPay(gearId, cardno, cardname);
return AjaxResult.success(payResVO);
}

View File

@ -21,9 +21,9 @@ public class JinShaBodyReq {
private String notify_url;
private String return_url;
private String sign;
private String cardname;
private String cardno;
/**
* 档位ID

View File

@ -8,8 +8,11 @@ public interface IJinShaService {
/**
* 支付
* @param gearId 档位ID
* @param cardno 银行卡号
* @param cardname 银行卡姓名
*/
PayResVO jinShaPay(Long gearId) throws Exception;
PayResVO jinShaPay(Long gearId, String cardno, String cardname) throws Exception;
/**

View File

@ -48,10 +48,20 @@ public class JinShaService implements IJinShaService {
@Autowired
private IAiRechargeGiftGearService aiRechargeGiftGearService;
@Autowired
private IAiRechargeGiftService aiRechargeGiftService;
@Autowired
private IExchangeRateService exchangeRateService;
@Override
public PayResVO jinShaPay(Long gearId) throws Exception {
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);
}
//充值挡位查询
AiRechargeGiftGear aiRechargeGiftGear = aiRechargeGiftGearService.selectAiRechargeGiftGearById(gearId);
@ -62,62 +72,86 @@ public class JinShaService implements IJinShaService {
// 使用汇率服务转换金额从CNY转换为目标货币默认INR
amount = exchangeRateService.convertAmount(amount, "USD", "INR");
JinShaBodyReq req = new JinShaBodyReq();
req.setAppid(appId);
req.setReturn_url(returnUrl + "/recharge");
req.setNotify_url(notifyUrl + "/api/pay/jinsha-callBack");
req.setAmount(amount);
// 1. 配置请求参数
TreeMap<String, Object> params = new TreeMap<>();
params.put("appid", req.getAppid());
// 生成订单号
String uuid = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8);
String dateTime = new SimpleDateFormat("yyyyMMdd").format(new Date());
String orderNo = dateTime + "js" + uuid;
params.put("orderno", orderNo);
params.put("amount", amount);
params.put("notify_url", req.getNotify_url());
params.put("return_url", req.getReturn_url());
StringBuilder append = this.append(params);
String sign = this.sign(append);
String formData = append + "&sign=" + sign;
// 2. 构建请求体form-urlencoded 格式
RequestBody requestBody = RequestBody.create(
MediaType.get("application/x-www-form-urlencoded;charset=utf-8"),
formData
);
// 3. 构建 POST 请求
// 金额转换为int类型去除小数部分
int amountInt = amount.intValue();
// 1. 配置签名参数按照key排序不包含notify_url和sign
TreeMap<String, Object> signParams = new TreeMap<>();
signParams.put("appid", appId);
signParams.put("amount", amountInt);
signParams.put("orderno", orderNo);
signParams.put("cardno", cardno);
signParams.put("cardname", cardname);
// 2. 生成签名
String sign = this.generateSign(signParams);
// 3. 构建请求参数使用FormBody.Builder自动处理URL编码
FormBody.Builder formBuilder = new FormBody.Builder();
formBuilder.add("appid", appId);
formBuilder.add("amount", String.valueOf(amountInt));
formBuilder.add("orderno", orderNo);
formBuilder.add("cardno", cardno);
formBuilder.add("cardname", cardname);
formBuilder.add("notify_url", notifyUrl + "/api/pay/jinsha-callBack");
formBuilder.add("sign", sign);
RequestBody requestBody = formBuilder.build();
// 5. 构建 POST 请求
Request request = new Request.Builder()
.url(url + "/api/pay")
// .header("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
.header("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
.post(requestBody)
.build();
// 4. 发送请求并获取响应
// 6. 发送请求并获取响应
Response response = OkHttpUtils.newCall(request).execute();
ResponseBody body = response.body();
if (null == body) {
log.error("kada支付请求的响应异常");
throw new Exception("kadapay responsebody is null");
log.error("jinsha支付请求的响应异常");
throw new Exception("jinshapay responsebody is null");
}
JinShaBodyRes jinShaBodyRes = objectMapper.readValue(body.string(), JinShaBodyRes.class);
String responseBody = body.string();
log.info("jinsha支付请求响应: {}", responseBody);
JinShaBodyRes jinShaBodyRes = objectMapper.readValue(responseBody, JinShaBodyRes.class);
// 检查响应code0表示成功其他值表示失败
Integer code = jinShaBodyRes.getCode();
if (code == null || code != 0) {
String msg = jinShaBodyRes.getMsg();
log.error("jinsha支付请求失败code: {}, msg: {}", code, msg);
throw new ServiceException(msg != null ? msg : "支付请求失败", code != null ? code : -1);
}
// 创建充值管理
AiUser userInfo = aiUserService.getUserInfo(SecurityUtils.getAiUserId());
AiRecharge aiRecharge = new AiRecharge();
aiRecharge.setOrderNum(orderNo);
aiRecharge.setUserId(SecurityUtils.getAiUserId());
aiRecharge.setAmount(amount);
aiRecharge.setGearId(req.getGearId());
aiRecharge.setGearId(gearId);
aiRecharge.setGearAmount(aiRechargeGiftGear.getRechargeAmount());
aiRecharge.setSource(userInfo.getSource());
AiRechargeGift aiRechargeGift = aiRechargeGiftService.selectAiRechargeGiftById(aiRechargeGiftGear.getRechargeId());
aiRecharge.setPayType(aiRechargeGift.getPayType());
// jinsha支付成功返回后不需要支付URL订单状态由回调更新
aiRechargeService.insertAiRecharge(aiRecharge);
PayResVO payResVO = new PayResVO();
payResVO.setOrderNo(orderNo);
payResVO.setPayUrl(jinShaBodyRes.getData().getPayurl());
// jinsha支付成功后不需要跳转支付页面直接返回订单号
return payResVO;
}
@Override
@Transactional
public AjaxResult jinShaCall(JinShaBodyCall req) {
log.info("jinsha支付回调订单号: {}, 状态: {}", req.getOrderno(), req.getStatus());
// 验证签名
TreeMap<String, Object> params = new TreeMap<>();
params.put("status", req.getStatus());
params.put("orderno", req.getOrderno());
@ -126,14 +160,58 @@ public class JinShaService implements IJinShaService {
StringBuilder append = this.append(params);
String sign = this.sign(append);
if (!sign.equals(req.getSign())) {
log.error("支付回调签名错误 {}", req.getOrderno());
return AjaxResult.error();
}
//充值成功处理
aiRechargeService.addRecharge(req.getOrderno());
return AjaxResult.success();
log.error("jinsha支付回调签名错误订单号: {}, 期望签名: {}, 实际签名: {}",
req.getOrderno(), sign, req.getSign());
return AjaxResult.error("签名验证失败");
}
// 处理订单状态
// status:0=>处理中, status:1=>成功, status:2=>失败
Integer status = req.getStatus();
if (status == null) {
log.error("jinsha支付回调状态为空订单号: {}", req.getOrderno());
return AjaxResult.error("状态为空");
}
if (status == 1) {
// 充值成功处理
log.info("jinsha支付成功订单号: {}", req.getOrderno());
aiRechargeService.addRecharge(req.getOrderno());
return AjaxResult.success();
} else if (status == 2) {
// 支付失败
log.warn("jinsha支付失败订单号: {}", req.getOrderno());
// 这里可以添加失败处理逻辑比如更新订单状态为失败
return AjaxResult.success();
} else {
// 处理中status:0
log.info("jinsha支付处理中订单号: {}", req.getOrderno());
return AjaxResult.success();
}
}
/**
* 生成签名
* 按照文档要求key=value&key=value&...&secret=secret然后MD5
*/
private String generateSign(TreeMap<String, Object> sortedParams) {
StringBuilder paramSb = new StringBuilder();
for (Map.Entry<String, Object> entry : sortedParams.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
// 拼接格式key=value&
paramSb.append(key).append("=").append(value).append("&");
}
// 最后添加secret
paramSb.append("secret=").append(secret);
String signSource = paramSb.toString();
log.debug("jinsha签名源字符串: {}", signSource);
return Md5Utils.hash(signSource);
}
/**
* 旧的签名方法回调使用
*/
private StringBuilder append(TreeMap<String, Object> sortedParams) {
StringBuilder paramSb = new StringBuilder();
for (Map.Entry<String, Object> entry : sortedParams.entrySet()) {