1
zj
2026-01-03 568f43099ef16b4a5ca00152a00d487b9954acdb
1
1 files modified
2 files added
207 ■■■■■ changed files
src/main/java/com/nq/service/impl/PayServiceImpl.java 107 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/utils/PaymentApiResponse.java 31 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/utils/PaymentSignUtil.java 69 ●●●●● patch | view | raw | blame | history
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 {
        // 示例参数
src/main/java/com/nq/utils/PaymentApiResponse.java
New file
@@ -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;
    }
}
src/main/java/com/nq/utils/PaymentSignUtil.java
New file
@@ -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;
        }
    }
}