无关风月
2025-07-22 74f666605450658b86e1b5ca076500aa341b6f49
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/PaymentUtil.java
@@ -7,9 +7,13 @@
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.other.util.UUIDUtil;
import com.ruoyi.other.util.payment.model.*;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.*;
/**
@@ -19,25 +23,25 @@
 */
@Slf4j
public class PaymentUtil {
   //微信公众号、微信小程序、微信 APP+/H5、云微小程序支付
   private static final String appId = "wxdeed472c98e42a54";
   private static final String appId = "wx049faf9c5234f31c";
   /**
    * 商户密钥
    */
   private static final String key = "925899fcc374430f9e4b4ba3db05b448";
   private static final String key = "ss369875124965782f148539657826321";
   /**
    * 商户号
    */
   private static final String merchantNo = "888122600004175";
   private static final String merchantNo = "1717539630";
   /**
    * 平台-报备商户号
    */
   private static final String sysTradeMerchantNo = "777168500885852";
   private static final String sysTradeMerchantNo = "";
   /**
    * 支付回调地址
    */
   private static final String callbackUrl = "https://www.qijisheng.top";
   private static final String callbackUrl = "https://221.182.45.100:8084";
   
   
   /**
@@ -101,8 +105,138 @@
      UniPayResult uniPayResult = JSON.parseObject(execute.body(), UniPayResult.class);
      return uniPayResult;
   }
   /**
    * native支付
    * @param orderNo           商户订单号
    * @param amount            订单金额
    * @param notifyUrl         服务器异步通知地址
    * @return
    */
   public static String nativePay(String orderNo, BigDecimal amount, String notifyUrl) throws Exception {
      int totalFee = amount.multiply(new BigDecimal("100")).intValue();
      String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
      // 构建 XML 请求体
      Map<String, Object> params = new HashMap<>();
      params.put("appid", appId);
      params.put("mch_id", merchantNo);
      params.put("nonce_str", UUIDUtil.getRandomCode(16));
      params.put("body", "积分充值");
      params.put("out_trade_no", orderNo);
      params.put("total_fee", totalFee);
//      params.put("spbill_create_ip", InetAddress.getLocalHost().getHostAddress());
      params.put("spbill_create_ip", "221.182.45.100");
      params.put("notify_url", "https://221.182.45.100:8084/undif");
      params.put("trade_type", "NATIVE");
      params.put("product_id", "1");
      String sign = sign1(JSONObject.from(params)); // 使用原来的 sign 方法
      params.put("sign", sign);
      String xmlBody = mapToXml(params); // 转换为 XML 字符串
      // 发送请求
      HttpRequest post = HttpUtil.createPost(url);
      post.header(Header.CONTENT_TYPE, "application/xml");
      post.body(xmlBody); // 发送原始 XML 字符串
      log.info("Native支付接口请求参数:" + xmlBody);
      HttpResponse execute = post.execute();
      log.info("Native支付接口请求响应:" + execute.body());
      if (execute.getStatus() != 200) {
         log.error("Native支付接口异常:" + execute.body());
         return null;
      }
      return execute.body();
   }
   private static String mapToXml(Map<String, Object> map) {
      StringBuilder sb = new StringBuilder();
      sb.append("<xml>");
      for (Map.Entry<String, Object> entry : map.entrySet()) {
         String key = entry.getKey();
         Object value = entry.getValue();
         if (value != null && !value.toString().isEmpty()) {
            sb.append("<").append(key).append(">");
            sb.append(value);
            sb.append("</").append(key).append(">");
         }
      }
      sb.append("</xml>");
      return sb.toString();
   }
   public static String sign1(JSONObject body) {
      Set<Map.Entry<String, Object>> entries = body.entrySet();
      List<Map.Entry<String, Object>> infoIds = new ArrayList<>(entries);
      // 排除 sign 字段本身
      infoIds.removeIf(entry -> "sign".equals(entry.getKey()));
      // 按 ASCII 顺序排序
      infoIds.sort(Map.Entry.comparingByKey());
      StringBuilder sb = new StringBuilder();
      for (Map.Entry<String, Object> entry : infoIds) {
         Object val = entry.getValue();
         if (val != null && !val.toString().trim().isEmpty()) {
            sb.append(entry.getKey()).append("=").append(val).append("&");
         }
      }
      // 最后拼接 &key=商户密钥
      sb.append("key=").append(key);
      String stringSignTemp = sb.toString();
      log.info("待签名串:{}", stringSignTemp);
      // 使用 MD5 加密
      return MD5AndKL.MD5(stringSignTemp);
   }
   /**
    * 微信下单的签名算法
    *
    * @param map
    * @return
    */
   private String weixinSignature(Map<String, Object> map) {
      try {
         Set<Map.Entry<String, Object>> entries = map.entrySet();
         List<Map.Entry<String, Object>> infoIds = new ArrayList<Map.Entry<String, Object>>(entries);
         // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
         Collections.sort(infoIds, new Comparator<Map.Entry<String, Object>>() {
            public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
               return (o1.getKey()).toString().compareTo(o2.getKey());
            }
         });
         // 构造签名键值对的格式
         StringBuilder sb = new StringBuilder();
         for (Map.Entry<String, Object> item : infoIds) {
            if (item.getKey() != null || item.getKey() != "") {
               String key = item.getKey();
               Object val = item.getValue();
               if (!(val == "" || val == null)) {
                  sb.append(key + "=" + val + "&");
               }
            }
         }
         sb.append("key=" + key);
         String sign = MD5AndKL.MD5Encode(sb.toString(), "UTF-8").toUpperCase(); //注:MD5签名方式
         return sign;
      } catch (Exception e) {
         e.printStackTrace();
      }
      return null;
   }
   public static void main(String[] args) throws Exception {
      SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
      String code = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5);
      String string = PaymentUtil.nativePay(code,new BigDecimal("0.1"),
            "/test"
      );
      System.err.println(string);
   }
   /**
    * 查询支付订单
    * @param orderNo   订单号
@@ -282,11 +416,5 @@
   }
   
   
   public static void main(String[] args) {
//      UniPayResult uniPayResult = PaymentUtil.uniPay("852963742", 0.01D, "测试商品", "这是用于对接支付测试的商品描述",
//            "", "/order/shopping-cart/shoppingCartPaymentCallback", "ooOrs64zHLuInkZ_GF0LpIN9_Rxc", "777168500885852");
//      PaymentUtil.queryOrder("852963742");
//      PaymentUtil.closeOrder("852963742");
   }
}