From 568f43099ef16b4a5ca00152a00d487b9954acdb Mon Sep 17 00:00:00 2001
From: zj <1772600164@qq.com>
Date: Sat, 03 Jan 2026 23:26:54 +0800
Subject: [PATCH] 1

---
 src/main/java/com/nq/utils/PaymentSignUtil.java       |   69 +++++++++++++++++
 src/main/java/com/nq/utils/PaymentApiResponse.java    |   31 +++++++
 src/main/java/com/nq/service/impl/PayServiceImpl.java |  107 ++++++++++++++++++++++++++
 3 files changed, 207 insertions(+), 0 deletions(-)

diff --git a/src/main/java/com/nq/service/impl/PayServiceImpl.java b/src/main/java/com/nq/service/impl/PayServiceImpl.java
index ea35e71..4d59e79 100644
--- a/src/main/java/com/nq/service/impl/PayServiceImpl.java
+++ b/src/main/java/com/nq/service/impl/PayServiceImpl.java
@@ -103,6 +103,8 @@
         String reqUrl = "https://api.watchglb.com/pay/web";
         // 支付2
         String uipReqRul = "https://v2.fastechservicepro.com/payin/unifiedorder";
+        // 支付3
+        String threeUrl = "https://www.copays.net/open-api/create-pay-order";
 
         User user = userService.getCurrentRefreshUser(request);
         if(ObjectUtils.isEmpty(user)){
@@ -115,6 +117,8 @@
             return getPaymentOne(tradeAmount, reqUrl,user,request);
         }else if(type == 2){//支付2
             return getPaymentTwo(tradeAmount, uipReqRul, user,request);
+        } else if(type == 3){//支付2
+            return getPaymentThree(tradeAmount, threeUrl, user,request);
         }else if(type == 1){
             return getPaymentZero(tradeAmount, uipReqRul, user,request); 
         }
@@ -211,6 +215,109 @@
         cipher.init(Cipher.ENCRYPT_MODE, k, ivParameterSpec);
         return cipher.doFinal(data);
     }
+
+    private ServerResponse getPaymentThree(String tradeAmount, String uipReqRul, User user, HttpServletRequest request) throws Exception {
+
+        // 配置参数(建议放到配置文件中)
+        String appId = "your_app_id_here"; // 从商户后台获取
+        String key = "your_key_here"; // 商户密钥
+        String payChannel = "INDIA_NATIVE"; // 支付通道,根据实际情况选择
+
+        // 生成商户订单号
+        String merchantOrderId = generatePayOrderId();
+
+        // 处理金额,保留两位小数
+        BigDecimal amount = new BigDecimal(tradeAmount);
+        amount = amount.setScale(2, BigDecimal.ROUND_HALF_UP);
+
+        // 构建请求参数
+        Map<String, String> params = new HashMap<>();
+        params.put("app_id", appId);
+        params.put("merchant_order_id", merchantOrderId);
+        params.put("amount", amount.toString());
+        params.put("pay_channel", payChannel);
+        params.put("notify_url", "https://api.durocaspitall.com/user/rechargeCallbackTwo.do"); // 异步通知地址
+        params.put("page_return_url", "https://yourdomain.com/pay/return"); // 前端返回地址
+
+        // 可选参数
+        if (user != null) {
+            String customerName = UserNameUtil.formatCustomerName(user.getNickName());
+            if (StringUtils.isNotEmpty(customerName)) {
+                params.put("customer_name", customerName);
+            }
+            if (StringUtils.isNotEmpty(user.getPhone())) {
+                params.put("customer_phone", user.getPhone());
+            }
+            params.put("customer_email", "test@gmail.com"); // 根据实际情况获取用户邮箱
+        }
+
+        // 生成签名(注意:签名生成时不需要包含sign参数本身)
+        String sign = PaymentSignUtil.generateSign(params, key);
+        params.put("sign", sign);
+
+        log.info("支付请求参数:{}", params);
+        log.info("生成的签名:{}", sign);
+
+        // 发送请求
+        String result = HttpClientUtil.doPost(uipReqRul, params, "utf-8");
+        log.info("支付返回参数:{}", result);
+
+        // 解析响应
+        ObjectMapper objectMapper = new ObjectMapper();
+        PaymentApiResponse response = objectMapper.readValue(result, PaymentApiResponse.class);
+
+        // 检查响应
+        if (!Integer.valueOf(200).equals(response.getCode())) {
+            log.error("支付下单失败,返回码:{},消息:{},请求参数:{}",
+                    response.getCode(), response.getMessage(), params);
+            return ServerResponse.createByErrorMsg("获取支付链接失败:" + response.getMessage(), request);
+        }
+
+        // 可选:验证返回签名
+        PaymentApiResponse.PaymentData responseData = response.getData();
+        Map<String, String> responseSignParams = new HashMap<>();
+        responseSignParams.put("merchant_id", responseData.getMerchantId());
+        responseSignParams.put("app_id", responseData.getAppId());
+        responseSignParams.put("system_order_id", responseData.getSystemOrderId());
+        responseSignParams.put("merchant_order_id", responseData.getMerchantOrderId());
+        responseSignParams.put("pay_url", responseData.getPayUrl());
+
+        boolean signValid = PaymentSignUtil.verifySign(responseSignParams, key, responseData.getSign());
+        if (!signValid) {
+            log.warn("返回签名验证失败,可能存在安全风险");
+        }
+
+        // 保存支付记录
+        PaymentRecharge paymentRecharge = new PaymentRecharge();
+        paymentRecharge.setUserId(user.getId());
+        paymentRecharge.setOrderNo(merchantOrderId); // 商户订单号
+        paymentRecharge.setMchOrderNo(responseData.getSystemOrderId()); // 平台订单号
+        paymentRecharge.setAmount(amount);
+        paymentRecharge.setStatus(1); // 1:已获取
+        paymentRecharge.setPaymentTime(new Date());
+        paymentRecharge.setCreatedAt(new Date());
+        paymentRecharge.setNotifyUrl(params.get("notify_url"));
+        paymentRecharge.setPayInfo(result);
+        paymentRechargeService.save(paymentRecharge);
+
+        // 保存用户充值记录
+        UserRecharge userRecharge = new UserRecharge();
+        userRecharge.setUserId(user.getId());
+        userRecharge.setNickName(user.getRealName());
+        userRecharge.setAgentId(user.getAgentId());
+        userRecharge.setOrderSn(merchantOrderId);
+        userRecharge.setPayChannel(payChannel); // 使用实际的支付通道
+        userRecharge.setPayAmt(amount);
+        userRecharge.setAddTime(new Date());
+        userRecharge.setPayTime(new Date());
+        userRecharge.setOrderStatus(0); // 审核中
+        userRecharge.setPayId(3); // 支付通道ID,根据实际情况设置
+        userRechargeMapper.insert(userRecharge);
+
+        // 返回支付URL
+        return ServerResponse.createBySuccess(responseData.getPayUrl());
+    }
+
     //支付2
     private ServerResponse getPaymentTwo(String tradeAmount, String uipReqRul, User user, HttpServletRequest request) throws UnsupportedEncodingException, NoSuchAlgorithmException, JsonProcessingException {
         // 示例参数
diff --git a/src/main/java/com/nq/utils/PaymentApiResponse.java b/src/main/java/com/nq/utils/PaymentApiResponse.java
new file mode 100644
index 0000000..d8f0c28
--- /dev/null
+++ b/src/main/java/com/nq/utils/PaymentApiResponse.java
@@ -0,0 +1,31 @@
+package com.nq.utils;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class PaymentApiResponse {
+    private Integer code;
+    private String message;
+    private PaymentData data;
+
+    @Data
+    public static class PaymentData {
+        @JsonProperty("merchant_id")
+        private String merchantId;
+
+        @JsonProperty("app_id")
+        private String appId;
+
+        @JsonProperty("system_order_id")
+        private String systemOrderId;
+
+        @JsonProperty("merchant_order_id")
+        private String merchantOrderId;
+
+        @JsonProperty("pay_url")
+        private String payUrl;
+
+        private String sign;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/nq/utils/PaymentSignUtil.java b/src/main/java/com/nq/utils/PaymentSignUtil.java
new file mode 100644
index 0000000..533d665
--- /dev/null
+++ b/src/main/java/com/nq/utils/PaymentSignUtil.java
@@ -0,0 +1,69 @@
+package com.nq.utils;
+
+import java.security.MessageDigest;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class PaymentSignUtil {
+
+    /**
+     * 生成签名
+     * @param params 请求参数Map
+     * @param key 密钥
+     * @return 签名
+     */
+    public static String generateSign(Map<String, String> params, String key) {
+        try {
+            // 第一步:去除空值参数
+            Map<String, String> sortedParams = new TreeMap<>();
+            for (Map.Entry<String, String> entry : params.entrySet()) {
+                if (entry.getValue() != null && !entry.getValue().trim().isEmpty()) {
+                    sortedParams.put(entry.getKey(), entry.getValue());
+                }
+            }
+
+            // 第二步:拼接字符串
+            StringBuilder stringA = new StringBuilder();
+            for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
+                stringA.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
+            }
+
+            // 去掉最后一个&
+            if (stringA.length() > 0) {
+                stringA.deleteCharAt(stringA.length() - 1);
+            }
+
+            // 拼接密钥
+            String stringB = stringA.toString() + "&key=" + key;
+
+            // 第三步:MD5并转为小写
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] digest = md.digest(stringB.getBytes("UTF-8"));
+            StringBuilder sign = new StringBuilder();
+            for (byte b : digest) {
+                sign.append(String.format("%02x", b));
+            }
+            return sign.toString().toLowerCase();
+
+        } catch (Exception e) {
+            throw new RuntimeException("生成签名失败", e);
+        }
+    }
+
+    /**
+     * 验证返回签名
+     * @param data 返回数据
+     * @param key 密钥
+     * @param sign 返回的签名
+     * @return 是否验证通过
+     */
+    public static boolean verifySign(Map<String, String> data, String key, String sign) {
+        try {
+            String generatedSign = generateSign(data, key);
+            return generatedSign.equals(sign);
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+}

--
Gitblit v1.9.3