Kaynağa Gözat

处理红包发送回调问题,多商户号不知道用的哪个商户号,循环获取商户号直到正确

cgp 2 gün önce
ebeveyn
işleme
222c0710de

+ 101 - 31
fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java

@@ -8,6 +8,7 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.TypeReference;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.annotation.DataScope;
 import com.fs.common.core.domain.R;
@@ -89,7 +90,6 @@ import com.google.gson.Gson;
 import com.hc.openapi.tool.fastjson.JSON;
 import io.netty.util.internal.StringUtil;
 import me.chanjar.weixin.common.error.WxErrorException;
-import org.apache.commons.collections4.CollectionUtils;
 import org.redisson.api.RedissonClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -106,7 +106,7 @@ import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
 import java.util.*;
-import java.util.function.Function;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 /**
@@ -983,42 +983,112 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
     @Override
     public String v3TransferNotify(String notifyData, HttpServletRequest request) {
         logger.info("zyp \n【收到转账回调】:{}", notifyData);
-        try {
-//            String json = configService.selectConfigByKey("redPacket.config");
 
-            String json = redisCache.getCacheObject("sys_config:redPacket.config.new");
-            if (StringUtil.isNullOrEmpty(json) || json.isEmpty()) {
-                json = configService.selectConfigByKey("redPacket.config");
-            }
+        // 获取所有商户号列表
+        List<String> mchIdList = getAvailableMchIds();
 
-            RedPacketConfig config = JSONUtil.toBean(json, RedPacketConfig.class);
-            //创建微信订单
-            WxPayConfig payConfig = new WxPayConfig();
-            BeanUtils.copyProperties(config, payConfig);
-            WxPayService wxPayService = new WxPayServiceImpl();
-            wxPayService.setConfig(payConfig);
-            SignatureHeader signatureHeader = new SignatureHeader();
-            signatureHeader.setTimeStamp(request.getHeader("Wechatpay-Timestamp"));
-            signatureHeader.setNonce(request.getHeader("Wechatpay-Nonce"));
-            signatureHeader.setSerial(request.getHeader("Wechatpay-Serial"));
-            signatureHeader.setSignature(request.getHeader("Wechatpay-Signature"));
-            TransferBillsNotifyResult result = wxPayService.parseTransferBillsNotifyV3Result(notifyData, signatureHeader);
-            logger.info("到零钱回调:{}", result.getResult());
-            if (result.getResult().getState().equals("SUCCESS")) {
-                R r = redPacketLogService.syncRedPacket(result.getResult().getOutBillNo(), result.getResult().getTransferBillNo());
-                logger.info("result:{}", r);
-                if (r.get("code").equals(200)) {
-                    return WxPayNotifyResponse.success("处理成功");
+        // 记录最后一次异常,用于日志
+        WxPayException lastException = null;
+
+        for (String mchId : mchIdList) {
+            try {
+                // 1. 获取该商户号的配置
+                RedPacketConfig config = getMchConfig(mchId);
+                logger.info("尝试商户号:{}", mchId);
+
+                // 2. 构建 WxPayService
+                WxPayConfig payConfig = new WxPayConfig();
+                BeanUtils.copyProperties(config, payConfig);
+                WxPayService wxPayService = new WxPayServiceImpl();
+                wxPayService.setConfig(payConfig);
+
+                // 3. 准备签名头
+                SignatureHeader signatureHeader = new SignatureHeader();
+                signatureHeader.setTimeStamp(request.getHeader("Wechatpay-Timestamp"));
+                signatureHeader.setNonce(request.getHeader("Wechatpay-Nonce"));
+                signatureHeader.setSerial(request.getHeader("Wechatpay-Serial"));
+                signatureHeader.setSignature(request.getHeader("Wechatpay-Signature"));
+
+                // 4. 尝试验签并解密
+                TransferBillsNotifyResult result = wxPayService.parseTransferBillsNotifyV3Result(notifyData, signatureHeader);
+
+                // 5. 验签成功,处理业务
+                logger.info("匹配到商户号:{},回调结果:{}", mchId, result.getResult());
+                if ("SUCCESS".equals(result.getResult().getState())) {
+                    R r = redPacketLogService.syncRedPacket(
+                            result.getResult().getOutBillNo(),
+                            result.getResult().getTransferBillNo()
+                    );
+                    logger.info("同步结果:{}", r);
+                    if (r.get("code").equals(200)) {
+                        return WxPayNotifyResponse.success("处理成功");
+                    } else {
+                        return WxPayNotifyResponse.fail("业务处理失败");
+                    }
                 } else {
                     return WxPayNotifyResponse.fail("");
                 }
-            } else {
-                return WxPayNotifyResponse.fail("");
+
+            } catch (WxPayException e) {
+                // 验签失败或解密失败,记录日志,继续尝试下一个商户号
+                logger.warn("商户号 {} 验签/解密失败:{}", mchId, e.getMessage());
+                lastException = e;
+                // 继续循环
+            } catch (Exception e) {
+                logger.error("商户号 {} 处理异常: {} - {}",
+                        mchId, e.getClass().getSimpleName(), e.getMessage());
+                lastException = new WxPayException(e.getMessage());
+                continue;
+            }
+        }
+
+        // 所有商户号均失败
+        logger.error("所有商户号配置均无法处理该回调,最后异常:", lastException);
+        return WxPayNotifyResponse.fail("无法匹配商户号配置");
+    }
+
+    /**
+     * 获取所有可用商户号列表(从数据库查询,缓存到 Redis)
+     * @return 商户号列表,不会返回 null
+     */
+    private List<String> getAvailableMchIds() {
+        String cacheKey = "sys_config:redPacket.allMchIds";
+
+        // 1. 从 Redis 获取
+        String cachedJson = redisCache.getCacheObject(cacheKey);
+        if (StringUtils.isNotBlank(cachedJson)) {
+            try {
+                // 解析 JSON 数组字符串 -> List<String>
+                return JSONUtil.parseArray(cachedJson).toList(String.class);
+            } catch (Exception e) {
+                logger.warn("解析缓存的商户号列表失败,将重新查库,错误:{}", e.getMessage());
+                // 缓存数据异常,删除缓存并重新查库
+                redisCache.deleteObject(cacheKey);
             }
-        } catch (WxPayException e) {
-            logger.error("zyp \n【转账回调异常】:{}", e.getReturnMsg());
-            return WxPayNotifyResponse.fail(e.getMessage());
         }
+
+        // 2. 缓存未命中或解析失败,从数据库查询
+        List<SysRedpacketConfigMore> configMoreList =
+                sysRedpacketConfigMoreMapper.selectSysRedpacketConfigMoreList(new SysRedpacketConfigMore());
+
+        if (CollectionUtils.isEmpty(configMoreList)) {
+            logger.warn("数据库中没有商户号配置,请检查");
+            // 缓存空列表,防穿透
+            redisCache.setCacheObject(cacheKey, "[]", 300, TimeUnit.SECONDS);
+            return Collections.emptyList();
+        }
+
+        // 提取商户号列表
+        List<String> mchIds = configMoreList.stream()
+                .map(SysRedpacketConfigMore::getMchId)
+                .distinct()
+                .collect(Collectors.toList());
+
+        // 3. 存入 Redis(存字符串数组的 JSON)
+        String jsonArray = JSONUtil.toJsonStr(mchIds);  // 如 ["1733024912","1701206124","1747857442"]
+        redisCache.setCacheObject(cacheKey, jsonArray, 30, TimeUnit.DAYS);
+
+        return mchIds;
     }
 
     @Override