Pārlūkot izejas kodu

微信支付代码提交

wangzhijun 3 dienas atpakaļ
vecāks
revīzija
c5acaf0c83

+ 17 - 0
nightFragrance-admin/src/main/resources/application-dev.yml

@@ -268,6 +268,23 @@ wechat:
   # 取消订单提醒消息模版ID
   techTemplate3: Ed4c0ra3qFl-WjgaxomYQWRCgjkO5NfJkibcFOTx3-Q
 
+# 微信支付
+wechatpay:
+  # appid
+  appId: wx9dc677bd41e82569
+  # appSecret
+  appSecret: 346ed2d83c0cab7816c73a1df2e04df3
+  # 商户号
+  mch-id: 1716293620
+  # 商户秘钥
+  mch-key: 29138927a706e34282df802feacfc18r
+  # 证书地址
+  cert-path: D:/apiclient_cert.pem
+  # 证书秘钥地址
+  cert-key-path: D:/apiclient_key.pem
+  # 异步回调地址
+  notify-url: https://48131076.r21.cpolar.top/wx/pay/payNotify
+
 # 防止XSS攻击
 xss:
   # 过滤开关

+ 18 - 0
nightFragrance-admin/src/main/resources/application-pro.yml

@@ -255,6 +255,24 @@ wechat:
   template-id-2: els5FNc0BtFbSKhxIjbzqGX_9FmxAWyBhjL95qVevYE
 
   menu: "{\"button\":[{\"type\":\"view\",\"name\":\"立即下单\",\"url\":\"https://city.baoxianzhanggui.com/fragrance/\"},{\"type\":\"view\",\"name\":\"查看商户\",\"url\":\"https://city.baoxianzhanggui.com/fragrance/#/pages/identify/identify\"},{\"name\":\"更多\",\"sub_button\":[{\"type\":\"view\",\"name\":\"技师招募\",\"url\":\"https://city.baoxianzhanggui.com/fragrance/#/pages/join/first_join\"},{\"type\":\"view\",\"name\":\"招商合作\",\"url\":\"https://city.baoxianzhanggui.com/fragrance/#/pages/join/teamwork\"},{\"type\":\"view\",\"name\":\"投诉举报\",\"url\":\"https://city.baoxianzhanggui.com/fragrance/#/pages/join/feedback\"},{\"type\":\"view\",\"name\":\"了解我们\",\"url\":\"https://city.baoxianzhanggui.com/fragrance/#/pages/join/understand\"}]}]}"
+
+# 微信支付
+wechatpay:
+  # appid
+  appId: wx9dc677bd41e82569
+  # appSecret
+  appSecret: 346ed2d83c0cab7816c73a1df2e04df3
+  # 商户号
+  mch-id: 1716293620
+  # 商户秘钥
+  mch-key: 29138927a706e34282df802feacfc18r
+  # 证书地址
+  cert-path: /nightFragrance/pay/apiclient_cert.pem
+  # 证书秘钥地址
+  cert-key-path: /nightFragrance/pay/apiclient_key.pem
+  # 异步回调地址
+  notify-url: https://48131076.r21.cpolar.top/wx/pay/payNotify
+
 # 防止XSS攻击
 xss:
   # 过滤开关

+ 46 - 0
nightFragrance-common/src/main/java/com/ylx/common/config/WechatPayConfig.java

@@ -0,0 +1,46 @@
+package com.ylx.common.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "wechatpay")
+public class WechatPayConfig {
+
+    /**
+     * appid.
+     */
+    private String appId;
+
+    /**
+     * appSecret.
+     */
+    private String appSecret;
+
+    /**
+     * 微信支付商户号.
+     */
+    private String mchId;
+
+    /**
+     * 微信支付商户密钥.
+     */
+    private String mchKey;
+
+    /**
+     * 异步回调地址
+     */
+    private String notifyUrl;
+
+    /**
+     * 证书地址
+     */
+    private String certPath;
+
+    /**
+     * 证书密钥地址
+     */
+    private String certKeyPath;
+}

+ 34 - 55
nightFragrance-common/src/main/java/com/ylx/common/config/WxPayBeanConfig.java

@@ -1,82 +1,61 @@
 package com.ylx.common.config;
 
 import cn.hutool.core.util.StrUtil;
+import com.github.binarywang.wxpay.config.WxPayConfig;
 import com.github.binarywang.wxpay.service.WxPayService;
-import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
+import com.github.binarywang.wxpay.service.impl.WxPayServiceApacheHttpImpl;
+import com.ylx.common.exception.ServiceException;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.io.IOUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.ResourceLoader;
-
-import java.io.InputStream;
-import java.security.KeyFactory;
-import java.security.PrivateKey;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.util.Base64;
 
 @Slf4j
 @Configuration
 public class WxPayBeanConfig {
 
     @Autowired
-    private WxPayConfig wxPayConfig;
-    @Autowired
-    private ResourceLoader resourceLoader;
+    private WechatPayConfig wxPayConfig;
 
     @Bean
-    public WxPayService wxPayService() throws Exception {
-        // SDK原生配置
-        com.github.binarywang.wxpay.config.WxPayConfig sdkConfig = new com.github.binarywang.wxpay.config.WxPayConfig();
+    public WxPayService wxPayService() {
+        // 1. 全局前置必填参数校验(启动即校验,提前暴露问题)
+        checkWxPayConfig();
+
+        // 2. 映射SDK原生配置
+        WxPayConfig sdkConfig = new WxPayConfig();
         sdkConfig.setAppId(wxPayConfig.getAppId());
         sdkConfig.setMchId(wxPayConfig.getMchId());
-        // v3密钥
         sdkConfig.setApiV3Key(wxPayConfig.getMchKey());
+        sdkConfig.setPrivateCertPath(wxPayConfig.getCertPath());
+        sdkConfig.setPrivateKeyPath(wxPayConfig.getCertKeyPath());
+        sdkConfig.setNotifyUrl(wxPayConfig.getNotifyUrl());
 
-        if (StrUtil.isBlank(wxPayConfig.getCertKeyPath())) {
-            log.warn("wx.cert-key-path未配置,跳过初始化微信支付服务");
-            return null;
-        }
-
-        // 读取私钥文件 apiclient_key.pem
-        Resource keyRes = resourceLoader.getResource(wxPayConfig.getCertKeyPath());
-        if(keyRes.exists()){
-            try (InputStream is = keyRes.getInputStream()) {
-                PrivateKey privateKey = loadPrivateKey(is);
-                sdkConfig.setPrivateKey(privateKey);
-                log.info("商户私钥文件加载成功:{}",wxPayConfig.getCertKeyPath());
-            } catch (Exception e) {
-                log.error("私钥文件存在但读取失败:{}",wxPayConfig.getCertKeyPath(),e);
-            }
-        }else{
-            // 文件不存在,只打日志,不中断启动
-            log.warn("商户私钥文件【{}】不存在,微信支付功能禁用",wxPayConfig.getCertKeyPath());
-        }
-
-        WxPayService payService = new WxPayServiceImpl();
+        // 3. V3推荐Apache HTTP实现,替换旧WxPayServiceImpl
+        WxPayService payService = new WxPayServiceApacheHttpImpl();
         payService.setConfig(sdkConfig);
+        log.info("微信支付V3客户端初始化完成,商户号:{}", wxPayConfig.getMchId());
         return payService;
     }
 
-    /** 从pem输入流读取RSA私钥 */
-    private PrivateKey loadPrivateKey(InputStream inputStream) throws Exception {
-        try {
-            // JDK8不能用inputStream.readAllBytes(),替换成IOUtils
-            byte[] bytes = IOUtils.toByteArray(inputStream);
-            String pem = new String(bytes)
-                    .replace("-----BEGIN PRIVATE KEY-----", "")
-                    .replace("-----END PRIVATE KEY-----", "")
-                    .replaceAll("\\s+", ""); // \s+ 清除所有换行、空格
-
-            byte[] decode = Base64.getDecoder().decode(pem);
-            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decode);
-            KeyFactory kf = KeyFactory.getInstance("RSA");
-            return kf.generatePrivate(spec);
-        } finally {
-            // 关闭流,防止资源泄漏
-            IOUtils.closeQuietly(inputStream);
+    /**
+     * 启动时校验所有必填支付配置,缺失直接抛异常阻止项目启动
+     */
+    private void checkWxPayConfig() {
+        if (StrUtil.isBlank(wxPayConfig.getAppId())) {
+            throw new ServiceException("微信支付配置缺失:wx.app-id不能为空");
+        }
+        if (StrUtil.isBlank(wxPayConfig.getMchId())) {
+            throw new ServiceException("微信支付配置缺失:wx.mch-id不能为空");
+        }
+        if (StrUtil.isBlank(wxPayConfig.getMchKey())) {
+            throw new ServiceException("微信支付配置缺失:wx.mch-key(APIv3密钥)不能为空");
+        }
+        if (StrUtil.isBlank(wxPayConfig.getCertPath()) || StrUtil.isBlank(wxPayConfig.getCertKeyPath())) {
+            throw new ServiceException("微信支付证书配置缺失:cert-path/cert-key-path证书路径不能为空");
+        }
+        if (StrUtil.isBlank(wxPayConfig.getNotifyUrl())) {
+            log.warn("微信支付回调地址notify-url未配置,支付回调无法接收");
         }
     }
 }

+ 1 - 1
nightFragrance-common/src/main/java/com/ylx/common/weixinPay/service/WxPayV3Service.java

@@ -56,7 +56,7 @@ public class WxPayV3Service {
             request.setPayer(payer);
 
             // 3. 发起支付
-            WxPayUnifiedOrderV3Result result = wxPayService.createOrderV3(TradeTypeEnum.JSAPI, request);
+            WxPayUnifiedOrderV3Result result = wxPayService.unifiedOrderV3(TradeTypeEnum.JSAPI, request);
             log.info("微信支付预支付成功,prepayId: {}", result.getPrepayId());
 
             // 4. 生成前端JSAPI支付参数