From 74f666605450658b86e1b5ca076500aa341b6f49 Mon Sep 17 00:00:00 2001
From: 无关风月 <443237572@qq.com>
Date: 星期二, 22 七月 2025 13:59:09 +0800
Subject: [PATCH] yml活动管理代码

---
 ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/WechatPayService.java |  114 +++++++++++++++++++++++++-------------------------------
 1 files changed, 51 insertions(+), 63 deletions(-)

diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/WechatPayService.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/WechatPayService.java
index dbf26be..9541643 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/WechatPayService.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/util/payment/wx/WechatPayService.java
@@ -4,7 +4,14 @@
 import com.alibaba.fastjson2.JSON;
 import com.ruoyi.common.core.domain.R;
 import com.ruoyi.other.util.payment.MD5AndKL;
+import com.ruoyi.other.util.payment.wx.WechatPayConfig;
+import com.ruoyi.other.util.payment.wx.XMLUtil;
+import org.apache.commons.codec.digest.DigestUtils;
 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.crypto.engines.AESEngine;
+import org.bouncycastle.crypto.paddings.PKCS7Padding;
+import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.bouncycastle.crypto.params.KeyParameter;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.bouncycastle.openssl.PEMParser;
 import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
@@ -12,6 +19,7 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
+import sun.misc.BASE64Decoder;
 import sun.security.util.DerInputStream;
 import sun.security.util.DerValue;
 
@@ -19,16 +27,19 @@
 import javax.crypto.Cipher;
 import javax.crypto.IllegalBlockSizeException;
 import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import java.io.*;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.net.InetAddress;
 import java.net.URL;
+import java.net.URLEncoder;
 import java.net.UnknownHostException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
@@ -38,6 +49,7 @@
 import java.security.spec.RSAPublicKeySpec;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * 微信支付服务类
@@ -48,16 +60,17 @@
     @Autowired
     private WechatPayConfig wechatPayConfig;
     private static final String RSA_PUBLIC_KEY_FILENAME = "wechat_rsa_public_key.pem";
-    private static final String CERT_FOLDER = "C:\\cert\\";
+    private static final String CERT_FOLDER = "cert/";
     /**
-     * 统一下单
+     * native统一下单
      * @param orderNumber 订单号
      * @param totalFee 总金额(分)
      * @param body 商品描述
-     * @param openid 用户openid
      * @return 预支付订单信息
      */
-    public R unifiedOrder(String orderNumber, String totalFee, String body, String openid, String callbackPath) throws Exception {
+    public Map<String, String> unifiedOrder(String orderNumber, String totalFee,
+                          String body,
+                           String callbackPath) throws Exception {
         int i = new BigDecimal(totalFee).multiply(new BigDecimal("100")).intValue();
         String hostAddress = null;
         try {
@@ -74,45 +87,28 @@
         params.put("out_trade_no", orderNumber);
         params.put("total_fee", String.valueOf(i) );
         params.put("spbill_create_ip", "221.182.45.100"); // 实际应用中应获取客户端IP
-        params.put("notify_url", wechatPayConfig.getCallbackPath()+callbackPath);
-        params.put("trade_type", "JSAPI");
-        params.put("openid", openid);
-
+        params.put("notify_url", "http://221.182.45.100:8084"+callbackPath);
+        params.put("trade_type", "NATIVE");
         // 生成签名
         String sign = weixinSignature(params);
         params.put("sign", sign);
-
         // 将参数转换为XML
         String xmlParams = XMLUtil.mapToXml(params).replaceFirst("^<\\?xml.+?\\?>\\s*", "");
-
         // 发送请求到微信支付统一下单接口
         String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
         String result = HttpUtil.post(url, xmlParams);
-
         // 解析返回结果
         Map<String, String> resultMap = XMLUtil.xmlToMap(result);
-
         // 验证签名
         if (!verifySign(resultMap, wechatPayConfig.getKey())) {
-            return R.fail("微信支付签名验证失败");
-//            throw new Exception("微信支付签名验证失败");
+            throw new Exception("微信支付签名验证失败");
         }
+        if (!resultMap.get("return_code").equals("SUCCESS")) {
+            throw new Exception("拉取支付失败");
 
-        // 构建小程序支付所需参数
-        Map<String, String> payParams = new HashMap<>();
-        payParams.put("appId", wechatPayConfig.getAppId());
-        payParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
-        payParams.put("nonceStr", generateNonceStr());
-        payParams.put("package", "prepay_id=" + resultMap.get("prepay_id"));
-        payParams.put("signType", "MD5");
-
-        // 生成支付签名
-        String paySign = weixinSignature(payParams);
-        payParams.put("paySign", paySign);
-
-        //给前端标识
-        payParams.put("payMethod","1");
-        return R.ok(JSON.toJSONString(payParams));
+        }
+        resultMap.put("code",orderNumber);
+        return resultMap;
     }
     /**
      * 微信下单的签名算法
@@ -436,12 +432,11 @@
         try {
             // 1. 解析回调XML数据
             if (StringUtils.isEmpty(xmlData)) {
-//                logger.error("退款回调数据为空");
                 return RefundCallbackResult.fail("回调数据为空");
             }
 
             //2.解析参数
-            System.err.println(xmlData);
+            System.out.println(xmlData);
             System.out.println("----------------------------------------");
             Map<String, String> resultMap = XMLUtil.xmlToMap(xmlData);
             System.out.println(resultMap.get("req_info"));
@@ -454,7 +449,7 @@
             }
 
             //4 使用商户API密钥解密req_info(AES-256-CBC算法)
-            String decryptData = wxDecrypt(resultMap.get("req_info"), wechatPayConfig.getKey());
+            String decryptData = decrypt(resultMap.get("req_info"), wechatPayConfig.getKey());
             Map<String, String> refundDetail = XMLUtil.xmlToMap(decryptData);
 
 
@@ -581,7 +576,7 @@
     }
 
     /**
-     * 加载公钥 返回PublicKey
+     * 加载公钥 返回PublicKey对象
      */
     public static PublicKey loadPublicKey(String pemContent) throws Exception {
         // 读取PEM文件内容
@@ -683,21 +678,9 @@
     }
 
     public static void main(String[] args) throws IOException {
-/*
-        try {
-            // 1. 加载公钥
-            PublicKey publicKey = loadPublicKey();
 
-            // 2. 加密数据
-            String sensitiveData = "用户名";
-            String encryptedData = encrypt(sensitiveData, publicKey);
+        String info="CjlaS7RVnPn7zzP5ByZDxUN7OrXGp1/DEdO0qahpIqDH/gTNHb/U7VmrVV0S4lXrIa0N8FEREC3CdIeT4XB5P4D0E8TSURu6J/cD01hFu28f0JDRfeips3vSpTgznRGyCfnUBDPYwyrVeP29Wac7WAb3CCcJf7OZWaweOUkaKjaBRa1GzMZcguSZnQJz0cD5Jb4HbTMvM0VAebfCY9aXdfFBIbm+cPYESo3awqwkNTQeT4V+FViw8f8sjkH0TScMgWBiSKmQC837BLD27yIGklqlYkDP2IMeiNw+b12qCAGszfp2vYd3X+HpViXkQQet3PJWYlAm55R+IgvschP7Ub65XzLINfQrJKrQUXiKKO2LwoSRSwZvfDkR8G8E8X59CnU2XvWKeos5Y0q8ckbJb97yI+09nNgMjYyJoVCVjTFgFMDEQ4+e3CpYRhD6V/3RBp+TvBwszldbRav2XEuCXL2kCJyJEAqLPMNyfYBSNF8z1btjyz0+y/xQQcySKlQInZ710FxSE7KwRSBQ92j9nDdlR7UxCrPVCkEd+GrVNSqqnyjNh1J/rPJPHvvGwkPPq72TKiw6ZgaIgIDhy0/lWHTclo4sjYAWuUVfg3CJ8dqkuQwVZ7i0+NiahIl78RtcUph8NR48yUgBkN7WhCcu5wLbg2tu8Qe0SIwHF+RW1x9Yc8akEkNbMd4xzs8lY5MYEU9V16U8RyWJuwPDph3RnmV8HQ+2hfzmjCvPkBwtfR8P5VdK86OIsHfnfQxAcPM2a86tOBBzFXPrLHgd2CRcDKH+MXTw7RSH/bk1PiMUAWF8TQsNDzgUlznJnkjiQxoym/4ZUf4C6072KKQHbp6bgBYkBhJLT2lmjVMNSX5b1SXM9eTQixRfq6MKGw3P8XJnKdofktVv+KtSzWQlW0C8p504NWACiExupF5EII7FG+xCWt7urWUbc4NRI36UFrKToQCLVv6UBCXt/t9iWlvs6SfuZhpCexeMmZWeiIldzRu87U9rXR46Hu7DAL8dZ+0ItsIZYThSIABzZgaLKggXlkjyAcbcPYKO7egrCmDtFhzHuh4uA3VeBylL3/ZLZ4FUedn/8L4e2iAu22Qj46ORlu17W5R8Ez9kubydeAgC9PkWnjptaubPxE0bjPN69tec";
 
-            System.out.println("加密结果(Base64):\n" + encryptedData);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }*/
-
-        String info="CjlaS7RVnPn7zzP5ByZDxUN7OrXGp1/DEdO0qahpIqDH/gTNHb/U7VmrVV0S4lXrIa0N8FEREC3CdIeT4XB5P4D0E8TSURu6J/cD01hFu2/uJOvcE6EeQH2xiRg/Wir4qcW7c6uTiLoqyirCQXcGzQb3CCcJf7OZWaweOUkaKjaBRa1GzMZcguSZnQJz0cD5jTMx+Tch5+b7jBq5PrTFxtMSH/DAG+kgkRazDFnEzkMeT4V+FViw8f8sjkH0TScMgWBiSKmQC837BLD27yIGklqlYkDP2IMeiNw+b12qCAGszfp2vYd3X+HpViXkQQet3PJWYlAm55R+IgvschP7Ub65XzLINfQrJKrQUXiKKO2LwoSRSwZvfDkR8G8E8X59CnU2XvWKeos5Y0q8ckbJb97yI+09nNgMjYyJoVCVjTGc7ghcYvWKbqanJ8bSFqiBCIqLSXsRR2DmJIxHq9fGE72kCJyJEAqLPMNyfYBSNF8z1btjyz0+y/xQQcySKlQInZ710FxSE7KwRSBQ92j9nDdlR7UxCrPVCkEd+GrVNSqqnyjNh1J/rPJPHvvGwkPPq72TKiw6ZgaIgIDhy0/lWHTclo4sjYAWuUVfg3CJ8dqkuQwVZ7i0+NiahIl78RtcUph8NR48yUgBkN7WhCcu5wLbg2tu8Qe0SIwHF+RW1x9Yc8akEkNbMd4xzs8lY5MYEU9V16U8RyWJuwPDph3RnmV8HQ+2hfzmjCvPkBwtfR8P5VdK86OIsHfnfQxAcPM2a86tOBBzFXPrLHgd2CRcDKH+MXTw7RSH/bk1PiMUAWF8TQsNDzgUlznJnkjiQxoym/4ZUf4C6072KKQHbp6bgBYkBhJLT2lmjVMNSX5b1SXM9eTQixRfq6MKGw3P8XJnKdofktVv+KtSzWQlW0C8p504NWACiExupF5EII7FG+xbTa/s7vxXCP7R98tpcQTGoQCLVv6UBCXt/t9iWlvs6SfuZhpCexeMmZWeiIldzRu87U9rXR46Hu7DAL8dZ+0ItsIZYThSIABzZgaLKggXlkjyAcbcPYKO7egrCmDtFhwN50V7hoXEQB8G5kf/lMuT5+xNE2FRmv7H2a0ttZiv4u17W5R8Ez9kubydeAgC9PkWnjptaubPxE0bjPN69tec";
         String key="fD0JzscfMf295SYtRK3MnPRjSCA4Gahr";
         try {
             String decrypted = decrypt(info, key);
@@ -709,26 +692,31 @@
 
 
     public static String decrypt(String encryptedStringA, String merchantKey) throws Exception {
-        try {
-            byte[] decode = Base64.getDecoder().decode(encryptedStringA);
-            String sign = MD5AndKL.MD5Encode(merchantKey, "UTF-8").toLowerCase();
-            System.out.println("MD5 Key: " + sign); // 调试输出
+        // 1. 对加密串A做base64解码,得到加密串B
+        byte[] decode = Base64.getDecoder().decode(encryptedStringA);
 
-            if (Security.getProvider("BC") == null) {
-                Security.addProvider(new BouncyCastleProvider());
-            }
+        // 2. 对商户key做md5,得到32位小写key*
+        String sign = MD5AndKL.MD5Encode(merchantKey, "UTF-8").toLowerCase();
 
-            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
-            byte[] aesKey = Arrays.copyOf(sign.getBytes("UTF-8"), 16); // 明确指定 UTF-8
-            SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey, "AES");
-            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
-
-            byte[] decryptedBytes = cipher.doFinal(decode);
-            return new String(decryptedBytes, "UTF-8"); // 明确指定 UTF-8
-        } catch (Exception e) {
-            System.err.println("解密失败: " + e.getMessage());
-            throw e;
+        // 3. 确保BouncyCastle提供者已添加
+        if (Security.getProvider("BC") == null) {
+            Security.addProvider(new BouncyCastleProvider());
         }
+
+        // 4. 使用AES-256-ECB解密(PKCS7Padding)
+        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
+
+        // 注意:微信要求使用AES-256,所以密钥应为32字节(256位)
+        // 如果MD5结果是32字节(256位),直接使用
+        byte[] aesKey = sign.getBytes(StandardCharsets.UTF_8);
+
+        SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey, "AES");
+        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
+
+        // 执行解密并指定UTF-8编码
+        byte[] decryptedBytes = cipher.doFinal(decode);
+        return new String(decryptedBytes, StandardCharsets.UTF_8);
     }
 
+
 }

--
Gitblit v1.7.1