diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index f7bdb5606..ebe4de02e 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -80,10 +80,11 @@ public interface WxPayService { /** * 仅根据商户号进行切换. - * 适用于一个商户号对应多个appId的场景,切换时会匹配第一个符合该商户号的配置. + * 适用于一个商户号对应多个appId的场景,切换时会匹配符合该商户号的配置. + * 注意:由于HashMap迭代顺序不确定,当存在多个匹配项时返回的配置是不可预测的,建议使用精确匹配方式. * * @param mchId 商户标识 - * @return 切换是否成功 boolean + * @return 切换是否成功,如果找不到匹配的配置则返回false */ boolean switchover(String mchId); @@ -98,10 +99,12 @@ public interface WxPayService { /** * 仅根据商户号进行切换. - * 适用于一个商户号对应多个appId的场景,切换时会匹配第一个符合该商户号的配置. + * 适用于一个商户号对应多个appId的场景,切换时会匹配符合该商户号的配置. + * 注意:由于HashMap迭代顺序不确定,当存在多个匹配项时返回的配置是不可预测的,建议使用精确匹配方式. * * @param mchId 商户标识 - * @return 切换成功 ,则返回当前对象,方便链式调用,否则抛出异常 + * @return 切换成功,则返回当前对象,方便链式调用 + * @throws WxRuntimeException 如果找不到匹配的配置 */ WxPayService switchoverTo(String mchId); diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java index dc880e0f9..4b51c498d 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java @@ -214,6 +214,12 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { @Override public boolean switchover(String mchId) { + // 参数校验 + if (StringUtils.isBlank(mchId)) { + log.error("商户号mchId不能为空"); + return false; + } + // 先尝试精确匹配(针对只有mchId没有appId的配置) if (this.configMap.containsKey(mchId)) { WxPayConfigHolder.set(mchId); @@ -246,6 +252,11 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { @Override public WxPayService switchoverTo(String mchId) { + // 参数校验 + if (StringUtils.isBlank(mchId)) { + throw new WxRuntimeException("商户号mchId不能为空"); + } + // 先尝试精确匹配(针对只有mchId没有appId的配置) if (this.configMap.containsKey(mchId)) { WxPayConfigHolder.set(mchId); diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/MultiAppIdSwitchoverTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/MultiAppIdSwitchoverTest.java index c88766bfa..c1c1460fe 100644 --- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/MultiAppIdSwitchoverTest.java +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/MultiAppIdSwitchoverTest.java @@ -220,4 +220,91 @@ public class MultiAppIdSwitchoverTest { success = singlePayService.switchover("single_mch_id"); assertTrue(success); } + + /** + * 测试空参数或null参数的处理 + */ + @Test + public void testSwitchoverWithNullOrEmptyMchId() { + // 测试 null 参数 + boolean success = payService.switchover(null); + assertFalse(success, "使用null作为mchId应该返回false"); + + // 测试空字符串 + success = payService.switchover(""); + assertFalse(success, "使用空字符串作为mchId应该返回false"); + + // 测试空白字符串 + success = payService.switchover(" "); + assertFalse(success, "使用空白字符串作为mchId应该返回false"); + } + + /** + * 测试 switchoverTo 方法对空参数或null参数的处理 + */ + @Test(expectedExceptions = WxRuntimeException.class) + public void testSwitchoverToWithNullMchId() { + payService.switchoverTo((String) null); + } + + @Test(expectedExceptions = WxRuntimeException.class) + public void testSwitchoverToWithEmptyMchId() { + payService.switchoverTo(""); + } + + @Test(expectedExceptions = WxRuntimeException.class) + public void testSwitchoverToWithBlankMchId() { + payService.switchoverTo(" "); + } + + /** + * 测试商户号存在包含关系的场景 + * 例如同时配置 "123" 和 "1234",验证前缀匹配不会错误匹配 + */ + @Test + public void testSwitchoverWithOverlappingMchIds() { + WxPayService testService = new WxPayServiceImpl(); + + // 配置两个有包含关系的商户号 + String mchId1 = "123"; + String mchId2 = "1234"; + String appId1 = "wx_app_123"; + String appId2 = "wx_app_1234"; + + WxPayConfig config1 = new WxPayConfig(); + config1.setMchId(mchId1); + config1.setAppId(appId1); + config1.setMchKey("key_123"); + + WxPayConfig config2 = new WxPayConfig(); + config2.setMchId(mchId2); + config2.setAppId(appId2); + config2.setMchKey("key_1234"); + + Map configMap = new HashMap<>(); + configMap.put(mchId1 + "_" + appId1, config1); + configMap.put(mchId2 + "_" + appId2, config2); + testService.setMultiConfig(configMap); + + // 切换到 "123",应该只匹配 "123_wx_app_123" + boolean success = testService.switchover(mchId1); + assertTrue(success); + assertEquals(testService.getConfig().getMchId(), mchId1); + assertEquals(testService.getConfig().getAppId(), appId1); + + // 切换到 "1234",应该只匹配 "1234_wx_app_1234" + success = testService.switchover(mchId2); + assertTrue(success); + assertEquals(testService.getConfig().getMchId(), mchId2); + assertEquals(testService.getConfig().getAppId(), appId2); + + // 精确切换验证 + success = testService.switchover(mchId1, appId1); + assertTrue(success); + assertEquals(testService.getConfig().getAppId(), appId1); + + success = testService.switchover(mchId2, appId2); + assertTrue(success); + assertEquals(testService.getConfig().getAppId(), appId2); + } }