Explorar o código

fix:账户从数据库查找

刘云鑫 hai 1 mes
pai
achega
07809534d2

+ 8 - 6
alien-dining/src/main/java/shop/alien/dining/controller/PaymentController.java

@@ -43,13 +43,14 @@ public class PaymentController {
             @ApiImplicitParam(name = "subject", value = "订单标题", required = true, paramType = "query", dataType = "String"),
             @ApiImplicitParam(name = "payType", value = "支付类型(alipay:支付宝, wechatPay:微信支付)", required = true, paramType = "query", dataType = "String"),
             @ApiImplicitParam(name = "payer", value = "支付用户", required = true, paramType = "query", dataType = "String"),
-            @ApiImplicitParam(name = "orderNo", value = "订单号", required = true, paramType = "query", dataType = "String")
+            @ApiImplicitParam(name = "orderNo", value = "订单号", required = true, paramType = "query", dataType = "String"),
+            @ApiImplicitParam(name = "storeId", value = "店铺ID,用于从 MySQL 获取该店铺支付配置(StorePaymentConfig)", required = true, paramType = "query", dataType = "Integer")
     })
     @RequestMapping("/prePay")
-    public R prePay(String price, String subject, String payType,String payer,String orderNo) {
-        log.info("PaymentController:prePay, price: {}, subject: {}, payType: {},payer:{},orderNo:{}", price, subject, payType,payer,orderNo);
+    public R prePay(String price, String subject, String payType, String payer, String orderNo, Integer storeId) {
+        log.info("PaymentController:prePay, price: {}, subject: {}, payType: {}, payer: {}, orderNo: {}, storeId: {}", price, subject, payType, payer, orderNo, storeId);
         try {
-            return paymentStrategyFactory.getStrategy(payType).createPrePayOrder(price, subject,payer,orderNo);
+            return paymentStrategyFactory.getStrategy(payType).createPrePayOrder(price, subject, payer, orderNo, storeId);
         } catch (Exception e) {
             return R.fail(e.getMessage());
         }
@@ -91,12 +92,13 @@ public class PaymentController {
      * 查询订单状态
      * @param transactionId 交易订单号(微信支付订单号/商户订单号)
      * @param payType 支付类型
+     * @param storeId 店铺ID,用于从 MySQL 获取该店铺支付配置
      * @return 订单状态信息
      */
     @RequestMapping("/searchOrderByOutTradeNoPath")
-    public R searchOrderByOutTradeNoPath(String transactionId, String payType) {
+    public R searchOrderByOutTradeNoPath(String transactionId, String payType, Integer storeId) {
         try {
-            return paymentStrategyFactory.getStrategy(payType).searchOrderByOutTradeNoPath(transactionId);
+            return paymentStrategyFactory.getStrategy(payType).searchOrderByOutTradeNoPath(transactionId, storeId);
         } catch (Exception e) {
             return R.fail(e.getMessage());
         }

+ 11 - 6
alien-dining/src/main/java/shop/alien/dining/strategy/payment/PaymentStrategy.java

@@ -13,14 +13,17 @@ import java.util.Map;
  * @date 2024/12/4
  */
 public interface PaymentStrategy {
-    /** 生成预支付订单
+    /** 生成预支付订单(本系统调用时需传 storeId 以从 MySQL 获取店铺支付配置)
      *
      * @param price 订单金额
      * @param subject 订单标题
+     * @param payer 支付者 openid
+     * @param orderNo 订单号
+     * @param storeId 店铺ID,本系统调用时必传,用于获取 StorePaymentConfig
      * @return 预支付订单信息
      * @throws Exception 生成异常
      */
-    R createPrePayOrder(String price, String subject, String payer, String orderNo) throws Exception;
+    R createPrePayOrder(String price, String subject, String payer, String orderNo, Integer storeId) throws Exception;
 
 
     /**
@@ -33,13 +36,14 @@ public interface PaymentStrategy {
     R handleNotify(String notifyData, HttpServletRequest request) throws Exception;
 
     /**
-     * 查询订单状态
+     * 查询订单状态(本系统调用时需传 storeId 以获取店铺支付配置)
      *
      * @param transactionId 交易订单号
+     * @param storeId 店铺ID,本系统调用时必传
      * @return 订单状态信息
      * @throws Exception 查询异常
      */
-    R searchOrderByOutTradeNoPath(String transactionId) throws Exception;
+    R searchOrderByOutTradeNoPath(String transactionId, Integer storeId) throws Exception;
 
     /**
      * 处理退款请求
@@ -51,13 +55,14 @@ public interface PaymentStrategy {
     String handleRefund(Map<String,String> params) throws Exception;
 
     /**
-     * 查询退款记录
+     * 查询退款记录(本系统调用时需传 storeId 以获取店铺支付配置)
      *
      * @param outRefundNo 退款订单号
+     * @param storeId 店铺ID,本系统调用时必传
      * @return 退款记录信息
      * @throws Exception 查询异常
      */
-    R searchRefundRecordByOutRefundNo(String outRefundNo ) throws Exception;
+    R searchRefundRecordByOutRefundNo(String outRefundNo, Integer storeId) throws Exception;
 
 
     /**

+ 168 - 172
alien-dining/src/main/java/shop/alien/dining/strategy/payment/impl/WeChatPaymentMininProgramStrategyImpl.java

@@ -1,6 +1,7 @@
 package shop.alien.dining.strategy.payment.impl;
 
 import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -16,16 +17,17 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
 import shop.alien.dining.service.StoreOrderService;
 import shop.alien.dining.strategy.payment.PaymentStrategy;
 import shop.alien.dining.util.WXPayUtility;
 import shop.alien.dining.util.WeChatPayUtil;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.StoreOrder;
+import shop.alien.entity.store.StorePaymentConfig;
+import shop.alien.mapper.StorePaymentConfigMapper;
 import shop.alien.util.common.constant.PaymentEnum;
-import shop.alien.util.system.OSUtil;
 
-import javax.annotation.PostConstruct;
 import javax.servlet.http.HttpServletRequest;
 import java.io.IOException;
 import java.io.UncheckedIOException;
@@ -58,50 +60,6 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
     @Value("${payment.wechatPay.host}")
     private String wechatPayApiHost;
     /**
-     * 微信支付商户id
-     */
-    @Value("${payment.wechatPay.business.mchId}")
-    private String mchId;
-    // TODO:小程序未注册-> 把下面的所有默认的去掉然后从配置文件中读取
-    /**
-     * 微信支付小程序应用id
-     */
-    @Value("${wechat.miniprogram.appId}")
-    private String appId;
-    /**
-     * 微信支付商户证书序列号
-     */
-    @Value("${payment.wechatPay.business.merchantSerialNumber}")
-    private String certificateSerialNo;
-    /**
-     * 微信支付公钥id
-     */
-    @Value("${payment.wechatPay.business.wechatPayPublicKeyId}")
-    private String wechatPayPublicKeyId;
-    /**
-     * 微信支付商户私钥路径
-     */
-    @Value("${payment.wechatPay.business.win.privateKeyPath}")
-    private String privateWinKeyPath;
-
-    /**
-     * 微信支付商户私钥路径(Linux环境)
-     */
-    @Value("${payment.wechatPay.business.linux.privateKeyPath}")
-    private String privateLinuxKeyPath;
-
-    /**
-     * 微信支付公钥路径
-     */
-    @Value("${payment.wechatPay.business.win.wechatPayPublicKeyFilePath}")
-    private String wechatWinPayPublicKeyFilePath;
-
-    /**
-     * 微信支付公钥路径(Linux环境)
-     */
-    @Value("${payment.wechatPay.business.linux.wechatPayPublicKeyFilePath}")
-    private String wechatLinuxPayPublicKeyFilePath;
-    /**
      * 微信支付预支付路径
      */
     @Value("${payment.wechatPay.business.miniProgram.prePayPath:/v3/pay/transactions/jsapi}")
@@ -125,96 +83,122 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
     @Value("${payment.wechatPay.searchOrderByOutTradeNoPath}")
     private String searchOrderByOutTradeNoPath;
 
-    @Value("${payment.wechatPay.business.apiV3key}")
-    private String apiV3key;
-
     private final StoreOrderService storeOrderService;
-
+    private final StorePaymentConfigMapper storePaymentConfigMapper;
     private final ObjectMapper objectMapper;
 
     private static String POSTMETHOD = "POST";
     private static String GETMETHOD = "GET";
 
-    private PrivateKey privateKey;
-    private PublicKey wechatPayPublicKey;
+    /**
+     * 根据店铺ID从 MySQL 获取支付配置(本系统内部调用时使用)
+     */
+    private StorePaymentConfig getConfigByStoreId(Integer storeId) {
+        if (storeId == null) {
+            return null;
+        }
+        LambdaQueryWrapper<StorePaymentConfig> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StorePaymentConfig::getStoreId, storeId);
+        return storePaymentConfigMapper.selectOne(wrapper);
+    }
 
+    /**
+     * 根据微信支付公钥序列号获取支付配置(外部回调如支付通知时使用,通过请求头 Wechatpay-Serial 判断)
+     */
+    private StorePaymentConfig getConfigByWechatPayPublicKeyId(String wechatPayPublicKeyId) {
+        if (!StringUtils.hasText(wechatPayPublicKeyId)) {
+            return null;
+        }
+        LambdaQueryWrapper<StorePaymentConfig> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StorePaymentConfig::getWechatPayPublicKeyId, wechatPayPublicKeyId);
+        return storePaymentConfigMapper.selectOne(wrapper);
+    }
 
-    @PostConstruct
-    public void setWeChatPaymentConfig() {
-        String privateKeyPath;
-        String wechatPayPublicKeyFilePath;
-        if ("windows".equals(OSUtil.getOsName())) {
-            privateKeyPath = privateWinKeyPath;
-            wechatPayPublicKeyFilePath = wechatWinPayPublicKeyFilePath;
-        } else {
-            privateKeyPath = privateLinuxKeyPath;
-            wechatPayPublicKeyFilePath = wechatLinuxPayPublicKeyFilePath;
+    /**
+     * 从 StorePaymentConfig 加载商户私钥
+     */
+    private PrivateKey loadPrivateKeyFromConfig(StorePaymentConfig config) {
+        if (config == null) {
+            return null;
+        }
+        if (config.getWechatPrivateKeyFile() != null && config.getWechatPrivateKeyFile().length > 0) {
+            String keyStr = new String(config.getWechatPrivateKeyFile(), StandardCharsets.UTF_8);
+            return WXPayUtility.loadPrivateKeyFromString(keyStr);
         }
-        this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyPath);
-        this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
+        if (StringUtils.hasText(config.getWechatPrivateKeyPath())) {
+            return WXPayUtility.loadPrivateKeyFromPath(config.getWechatPrivateKeyPath());
+        }
+        return null;
     }
 
-    @Override
-    public R createPrePayOrder(String price, String subject, String payer, String orderNo) throws Exception {
+    /**
+     * 从 StorePaymentConfig 加载微信支付公钥
+     */
+    private PublicKey loadPublicKeyFromConfig(StorePaymentConfig config) {
+        if (config == null) {
+            return null;
+        }
+        if (config.getWechatPayPublicKeyFile() != null && config.getWechatPayPublicKeyFile().length > 0) {
+            String keyStr = new String(config.getWechatPayPublicKeyFile(), StandardCharsets.UTF_8);
+            return WXPayUtility.loadPublicKeyFromString(keyStr);
+        }
+        if (StringUtils.hasText(config.getWechatPayPublicKeyFilePath())) {
+            return WXPayUtility.loadPublicKeyFromPath(config.getWechatPayPublicKeyFilePath());
+        }
+        return null;
+    }
 
+    @Override
+    public R createPrePayOrder(String price, String subject, String payer, String orderNo, Integer storeId) throws Exception {
+        // 本系统调用:通过 storeId 从 MySQL 获取店铺支付配置
+        if (storeId == null) {
+            log.warn("createPrePayOrder 缺少 storeId,无法获取支付配置");
+            return R.fail("店铺ID不能为空");
+        }
+        StorePaymentConfig config = getConfigByStoreId(storeId);
+        if (config == null) {
+            log.warn("未找到店铺支付配置 storeId={}", storeId);
+            return R.fail("未找到该店铺的微信支付配置");
+        }
+        PrivateKey privateKey = loadPrivateKeyFromConfig(config);
+        if (privateKey == null) {
+            return R.fail("店铺微信支付私钥未配置或加载失败");
+        }
+        String appId = config.getWechatMiniAppId() != null ? config.getWechatMiniAppId() : config.getWechatAppId();
+        if (!StringUtils.hasText(appId)) {
+            return R.fail("店铺微信小程序 appId 未配置");
+        }
+        String mchId = config.getWechatMchId();
+        if (!StringUtils.hasText(mchId)) {
+            return R.fail("店铺微信支付商户号未配置");
+        }
 
         DirectAPIv3JsapiPrepayRequest request = new DirectAPIv3JsapiPrepayRequest();
         request.appid = appId;
         request.mchid = mchId;
         request.description = subject;
         request.outTradeNo = orderNo;
-//        request.timeExpire = "2018-06-08T10:34:56+08:00";
-//        request.attach = "自定义数据说明";
         request.notifyUrl = prePayNotifyUrl;
-//        request.goodsTag = "WXG";
-//        request.supportFapiao = false;
         request.amount = new CommonAmountInfo();
         request.amount.total = Long.parseLong(price);
-//        request.amount.currency = "CNY";
         request.payer = new JsapiReqPayerInfo();
         request.payer.openid = payer;
-        /*request.detail = new CouponInfo();
-        request.detail.costPrice = 608800L;
-        request.detail.invoiceId = "微信123";
-        request.detail.goodsDetail = new ArrayList<>();
-        {
-            GoodsDetail goodsDetailItem = new GoodsDetail();
-            goodsDetailItem.merchantGoodsId = "1246464644";
-            goodsDetailItem.wechatpayGoodsId = "1001";
-            goodsDetailItem.goodsName = "iPhoneX 256G";
-            goodsDetailItem.quantity = 1L;
-            goodsDetailItem.unitPrice = 528800L;
-            request.detail.goodsDetail.add(goodsDetailItem);
-        };*/
-        /*request.sceneInfo = new CommonSceneInfo();
-        request.sceneInfo.payerClientIp = "14.23.150.211";
-        request.sceneInfo.deviceId = "013467007045764";
-        request.sceneInfo.storeInfo = new StoreInfo();
-        request.sceneInfo.storeInfo.id = "0001";
-        request.sceneInfo.storeInfo.name = "腾讯大厦分店";
-        request.sceneInfo.storeInfo.areaCode = "440305";
-        request.sceneInfo.storeInfo.address = "广东省深圳市南山区科技中一道10000号";*/
-/*        request.settleInfo = new SettleInfo();
-        request.settleInfo.profitSharing = false;*/
         try {
-            DirectAPIv3JsapiPrepayResponse response = doCreatePrePayOrder(request);
-            // TODO: 请求成功,继续业务逻辑
+            DirectAPIv3JsapiPrepayResponse response = doCreatePrePayOrder(request, config, privateKey);
             log.info("微信预支付订单创建成功,预支付ID:{}", response.prepayId);
-            Map<String,String> result = new HashMap<>();
-            response.prepayId = "prepay_id="+response.prepayId;
+            Map<String, String> result = new HashMap<>();
+            response.prepayId = "prepay_id=" + response.prepayId;
             result.put("prepayId", response.prepayId);
             result.put("appId", appId);
             result.put("mchId", mchId);
             result.put("orderNo", request.outTradeNo);
-            long timestamp = System.currentTimeMillis() / 1000; // 时间戳
-            String nonce = WXPayUtility.createNonce(32); // 随机字符串
+            long timestamp = System.currentTimeMillis() / 1000;
+            String nonce = WXPayUtility.createNonce(32);
             String message = String.format("%s\n%s\n%s\n%s\n", appId, timestamp, nonce, response.prepayId);
-//            String sign = WXPayUtility.sign(message, sha256withRSA, privateKey);
-
             Signature sign = Signature.getInstance("SHA256withRSA");
             sign.initSign(privateKey);
             sign.update(message.getBytes(StandardCharsets.UTF_8));
-            result.put("signType","RSA");
+            result.put("signType", "RSA");
             result.put("sign", Base64.getEncoder().encodeToString(sign.sign()));
             result.put("timestamp", String.valueOf(timestamp));
             result.put("nonce", nonce);
@@ -228,58 +212,47 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
     @Override
     public R handleNotify(String notifyData, HttpServletRequest request) throws Exception {
         log.info("[微信支付回调] 进入 handleNotify, notifyData 长度={}", notifyData != null ? notifyData.length() : 0);
-        /*{
-    "id": "EV-2018022511223320873",
-    "create_time": "2015-05-20T13:29:35+08:00",
-    "resource_type": "encrypt-resource",
-    "event_type": "TRANSACTION.SUCCESS",
-    "summary": "支付成功",
-    "resource": {
-        "original_type": "transaction",
-        "algorithm": "AEAD_AES_256_GCM",
-        "ciphertext": "",
-        "associated_data": "",
-        "nonce": ""
-    }
-}*/
-        // 1. 提取微信支付回调请求头中的验签参数(对应图片里的4个核心参数)
-        String serial = request.getHeader("Wechatpay-Serial"); // 证书序列号/公钥ID
-        String signature = request.getHeader("Wechatpay-Signature"); // 签名值
-        String timestamp = request.getHeader("Wechatpay-Timestamp"); // 时间戳
-        String nonce = request.getHeader("Wechatpay-Nonce"); // 随机字符串
-
-        // 2. 校验核心验签参数是否为空
+        // 外部回调:通过请求头 Wechatpay-Serial 从 MySQL 查找对应店铺的支付配置
+        String serial = request.getHeader("Wechatpay-Serial");
+        String signature = request.getHeader("Wechatpay-Signature");
+        String timestamp = request.getHeader("Wechatpay-Timestamp");
+        String nonce = request.getHeader("Wechatpay-Nonce");
+
         if (serial == null || signature == null || timestamp == null || nonce == null) {
             log.warn("微信支付回调验签失败:核心头参数缺失 serial={}, signature={}, timestamp={}, nonce={}",
                     serial, signature, timestamp, nonce);
             return R.fail("验签参数缺失");
         }
 
-        // 2.1 签名探测:微信会发 WECHATPAY/SIGNTEST/ 开头的 Signature 检测商户是否正确验签,需直接返回成功
         if (signature.startsWith("WECHATPAY/SIGNTEST/")) {
             log.info("[微信支付回调] 收到签名探测请求,直接应答成功");
             return R.success("OK");
         }
 
+        StorePaymentConfig config = getConfigByWechatPayPublicKeyId(serial);
+        if (config == null) {
+            log.warn("微信支付回调:未找到公钥序列号对应的店铺配置 serial={}", serial);
+            return R.fail("未找到对应支付配置");
+        }
+        PublicKey wechatPayPublicKey = loadPublicKeyFromConfig(config);
+        if (wechatPayPublicKey == null) {
+            log.warn("微信支付回调:加载公钥失败 serial={}", serial);
+            return R.fail("验签公钥加载失败");
+        }
+
         StringBuilder signStr = new StringBuilder();
-        signStr.append(timestamp).append("\n"); // 第一行:应答时间戳
-        signStr.append(nonce).append("\n");     // 第二行:应答随机串
-        signStr.append(notifyData).append("\n");      // 第三行:应答报文主体(末尾必须加\n
+        signStr.append(timestamp).append("\n");
+        signStr.append(nonce).append("\n");
+        signStr.append(notifyData).append("\n");
         Signature sign = Signature.getInstance("SHA256withRSA");
-        // 步骤2:Base64解码签名串(对应命令行openssl base64 -d逻辑)
         byte[] signatureBytes = Base64.getDecoder().decode(signature);
-
-        // 步骤3:初始化SHA256withRSA签名验证器(对应命令行-sha256参数)
         sign.initVerify(wechatPayPublicKey);
-
-        // 步骤4:传入验签名串(编码为UTF-8,对应命令行EOF里的内容)
         sign.update(signStr.toString().getBytes(StandardCharsets.UTF_8));
 
-        // 步骤5:执行验签(对应命令行-verify逻辑)
         if (sign.verify(signatureBytes)) {
-            // 文档要求:验签通过后先应答(5 秒内),再异步处理业务,避免超时导致微信重复回调
             final String notifyDataCopy = notifyData;
-            CompletableFuture.runAsync(() -> processNotifyBusiness(notifyDataCopy));
+            final StorePaymentConfig configCopy = config;
+            CompletableFuture.runAsync(() -> processNotifyBusiness(notifyDataCopy, configCopy));
             return R.success("OK");
         } else {
             return R.fail("Verified error");
@@ -288,9 +261,14 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
 
     /**
      * 异步处理回调业务:解密并更新订单状态(文档建议应答后再处理业务,避免超时)
+     * @param config 已通过 Wechatpay-Serial 解析得到的店铺支付配置,内含 apiV3Key
      */
-    private void processNotifyBusiness(String notifyData) {
+    private void processNotifyBusiness(String notifyData, StorePaymentConfig config) {
         try {
+            if (config == null || !StringUtils.hasText(config.getApiV3Key())) {
+                log.warn("微信支付回调:无可用 apiV3Key 无法解密");
+                return;
+            }
             JsonNode rootNode = objectMapper.readTree(notifyData);
             JsonNode resourceNode = rootNode.get("resource");
             if (resourceNode == null) {
@@ -299,7 +277,6 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
             }
             String encryptAlgorithm = resourceNode.get("algorithm").asText();
             String resourceNonce = resourceNode.get("nonce").asText();
-            // associated_data 选填,可能为空(文档:该字段可能为空)
             String associatedData = resourceNode.has("associated_data") && !resourceNode.get("associated_data").isNull()
                     ? resourceNode.get("associated_data").asText() : "";
             String ciphertext = resourceNode.get("ciphertext").asText();
@@ -308,7 +285,7 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
                 return;
             }
             String plainBusinessData = WeChatPayUtil.decrypt(
-                    apiV3key, resourceNonce, associatedData, ciphertext);
+                    config.getApiV3Key(), resourceNonce, associatedData, ciphertext);
             log.info("微信支付回调解密后的业务信息:{}", plainBusinessData);
             JSONObject jsonObject = JSONObject.parseObject(plainBusinessData);
             String tradeState = jsonObject.getString("trade_state");
@@ -335,13 +312,25 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
     }
 
     @Override
-    public R searchOrderByOutTradeNoPath(String transactionId) throws Exception {
-        log.info("查询微信支付订单状态,交易订单号:{}", transactionId);
+    public R searchOrderByOutTradeNoPath(String transactionId, Integer storeId) throws Exception {
+        log.info("查询微信支付订单状态,交易订单号:{}, storeId:{}", transactionId, storeId);
+        if (storeId == null) {
+            return R.fail("店铺ID不能为空");
+        }
+        StorePaymentConfig config = getConfigByStoreId(storeId);
+        if (config == null) {
+            return R.fail("未找到该店铺的微信支付配置");
+        }
+        PrivateKey privateKey = loadPrivateKeyFromConfig(config);
+        PublicKey publicKey = loadPublicKeyFromConfig(config);
+        if (privateKey == null || publicKey == null) {
+            return R.fail("店铺微信支付密钥未配置或加载失败");
+        }
         QueryByWxTradeNoRequest request = new QueryByWxTradeNoRequest();
         request.transactionId = transactionId;
-        request.mchid = mchId;
+        request.mchid = config.getWechatMchId();
         try {
-            DirectAPIv3QueryResponse response = searchOrderRun(request);
+            DirectAPIv3QueryResponse response = searchOrderRun(request, config, privateKey, publicKey);
             return R.data(response);
         } catch (WXPayUtility.ApiException e) {
             log.error("查询微信支付订单状态失败,状态码:{},错误信息:{}", e.getErrorCode(), e.getMessage());
@@ -349,11 +338,14 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
         }
     }
 
-    public DirectAPIv3QueryResponse searchOrderRun(QueryByWxTradeNoRequest request) {
+    public DirectAPIv3QueryResponse searchOrderRun(QueryByWxTradeNoRequest request,
+                                                   StorePaymentConfig config,
+                                                   PrivateKey privateKey,
+                                                   PublicKey wechatPayPublicKey) {
         String uri = searchOrderByOutTradeNoPath;
         uri = uri.replace("{out_trade_no}", WXPayUtility.urlEncode(request.transactionId));
         Map<String, Object> args = new HashMap<>();
-        args.put("mchid", mchId);
+        args.put("mchid", request.mchid);
         String queryString = WXPayUtility.urlEncode(args);
         if (!queryString.isEmpty()) {
             uri = uri + "?" + queryString;
@@ -361,21 +353,17 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
 
         Request.Builder reqBuilder = new Request.Builder().url(wechatPayApiHost + uri);
         reqBuilder.addHeader("Accept", "application/json");
-        reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
-        reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchId, certificateSerialNo, privateKey, GETMETHOD, uri, null));
+        reqBuilder.addHeader("Wechatpay-Serial", config.getWechatPayPublicKeyId());
+        reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(request.mchid, config.getMerchantSerialNumber(), privateKey, GETMETHOD, uri, null));
         reqBuilder.method(GETMETHOD, null);
         Request httpRequest = reqBuilder.build();
 
-        // 发送HTTP请求
         OkHttpClient client = new OkHttpClient.Builder().build();
         try (Response httpResponse = client.newCall(httpRequest).execute()) {
             String respBody = WXPayUtility.extractBody(httpResponse);
             if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
-                // 2XX 成功,验证应答签名
-                WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
+                WXPayUtility.validateResponse(config.getWechatPayPublicKeyId(), wechatPayPublicKey,
                         httpResponse.headers(), respBody);
-
-                // 从HTTP应答报文构建返回数据
                 return WXPayUtility.fromJson(respBody, DirectAPIv3QueryResponse.class);
             } else {
                 throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
@@ -391,21 +379,31 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
     }
 
     @Override
-    public R searchRefundRecordByOutRefundNo(String outRefundNo) throws Exception {
-        // 1. 初始化日志(推荐使用SLF4J,替代System.out.println)
+    public R searchRefundRecordByOutRefundNo(String outRefundNo, Integer storeId) throws Exception {
         Logger logger = LoggerFactory.getLogger(this.getClass());
 
-        // 2. 参数校验(前置防御,避免无效请求)
         if (outRefundNo == null || outRefundNo.trim().isEmpty()) {
             logger.error("微信退款查询失败:外部退款单号为空");
             return R.fail("外部退款单号不能为空");
         }
+        if (storeId == null) {
+            return R.fail("店铺ID不能为空");
+        }
+        StorePaymentConfig config = getConfigByStoreId(storeId);
+        if (config == null) {
+            return R.fail("未找到该店铺的微信支付配置");
+        }
+        PrivateKey privateKey = loadPrivateKeyFromConfig(config);
+        PublicKey publicKey = loadPublicKeyFromConfig(config);
+        if (privateKey == null || publicKey == null) {
+            return R.fail("店铺微信支付密钥未配置或加载失败");
+        }
 
         QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
         request.setOutRefundNo(outRefundNo);
 
         try {
-            Refund response = doSearchRefundRecordByOutRefundNo(request);
+            Refund response = doSearchRefundRecordByOutRefundNo(request, config, privateKey, publicKey);
 
             // 3. 空值校验(避免response为空导致空指针)
             if (response == null) {
@@ -463,26 +461,25 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
         return PaymentEnum.WECHAT_PAY_MININ_PROGRAM.getType();
     }
 
-    public Refund doSearchRefundRecordByOutRefundNo(QueryByOutRefundNoRequest request) {
+    public Refund doSearchRefundRecordByOutRefundNo(QueryByOutRefundNoRequest request,
+                                                   StorePaymentConfig config,
+                                                   PrivateKey privateKey,
+                                                   PublicKey wechatPayPublicKey) {
         String uri = searchRefundStatusByOutRefundNoPath;
         uri = uri.replace("{out_refund_no}", WXPayUtility.urlEncode(request.getOutRefundNo()));
         Request.Builder reqBuilder = new Request.Builder().url(wechatPayApiHost + uri);
         reqBuilder.addHeader("Accept", "application/json");
-        reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
-        reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchId, certificateSerialNo, privateKey, GETMETHOD, uri, null));
+        reqBuilder.addHeader("Wechatpay-Serial", config.getWechatPayPublicKeyId());
+        reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(config.getWechatMchId(), config.getMerchantSerialNumber(), privateKey, GETMETHOD, uri, null));
         reqBuilder.method(GETMETHOD, null);
         Request httpRequest = reqBuilder.build();
 
-        // 发送HTTP请求
         OkHttpClient client = new OkHttpClient.Builder().build();
         try (Response httpResponse = client.newCall(httpRequest).execute()) {
             String respBody = WXPayUtility.extractBody(httpResponse);
             if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
-                // 2XX 成功,验证应答签名
-                WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
+                WXPayUtility.validateResponse(config.getWechatPayPublicKeyId(), wechatPayPublicKey,
                         httpResponse.headers(), respBody);
-
-                // 从HTTP应答报文构建返回数据
                 return WXPayUtility.fromJson(respBody, Refund.class);
             } else {
                 throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
@@ -492,29 +489,28 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
         }
     }
 
-    public DirectAPIv3JsapiPrepayResponse doCreatePrePayOrder(DirectAPIv3JsapiPrepayRequest request) {
+    public DirectAPIv3JsapiPrepayResponse doCreatePrePayOrder(DirectAPIv3JsapiPrepayRequest request,
+                                                             StorePaymentConfig config,
+                                                             PrivateKey privateKey) {
         String uri = prePayPath;
         String reqBody = WXPayUtility.toJson(request);
 
         Request.Builder reqBuilder = new Request.Builder().url(wechatPayApiHost + uri);
         reqBuilder.addHeader("Accept", "application/json");
-        reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
-        reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchId, certificateSerialNo,privateKey, POSTMETHOD, uri, reqBody));
+        reqBuilder.addHeader("Wechatpay-Serial", config.getWechatPayPublicKeyId());
+        reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(config.getWechatMchId(), config.getMerchantSerialNumber(), privateKey, POSTMETHOD, uri, reqBody));
         reqBuilder.addHeader("Content-Type", "application/json");
         RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
         reqBuilder.method(POSTMETHOD, requestBody);
         Request httpRequest = reqBuilder.build();
 
-        // 发送HTTP请求
         OkHttpClient client = new OkHttpClient.Builder().build();
         try (Response httpResponse = client.newCall(httpRequest).execute()) {
             String respBody = WXPayUtility.extractBody(httpResponse);
             if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
-                // 2XX 成功,验证应答签名
-                WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
+                PublicKey wechatPayPublicKey = loadPublicKeyFromConfig(config);
+                WXPayUtility.validateResponse(config.getWechatPayPublicKeyId(), wechatPayPublicKey,
                         httpResponse.headers(), respBody);
-
-                // 从HTTP应答报文构建返回数据
                 return WXPayUtility.fromJson(respBody, DirectAPIv3JsapiPrepayResponse.class);
             } else {
                 throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());