优化多公众号支持代码

This commit is contained in:
Binary Wang
2019-03-29 21:28:23 +08:00
parent d17bb257f0
commit fb6efe9e0b
5 changed files with 116 additions and 67 deletions

View File

@ -5,6 +5,7 @@ import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor; import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.mp.api.impl.BaseWxMpServiceImpl;
import me.chanjar.weixin.mp.bean.WxMpSemanticQuery; import me.chanjar.weixin.mp.bean.WxMpSemanticQuery;
import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo; import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
@ -304,42 +305,49 @@ public interface WxMpService {
WxMpConfigStorage getWxMpConfigStorage(); WxMpConfigStorage getWxMpConfigStorage();
/** /**
* 注入 {@link WxMpConfigStorage} 的实现. * 设置 {@link WxMpConfigStorage} 的实现. 兼容老版本
*/ */
void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider); void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider);
/** /**
* {@link Map<String, WxMpConfigStorage>} 加入新的 {@link WxMpConfigStorage},适用于动态添加新的微信应用 * {@link Map<String, WxMpConfigStorage>} 加入新的 {@link WxMpConfigStorage},适用于动态添加新的微信公众号配置
* @param configStorages * @param configStorage 新的微信配置
*/ */
void addWxMpConfigStorage(String label, WxMpConfigStorage configStorages); void addConfigStorage(String mpId, WxMpConfigStorage configStorage);
/** /**
* 从{@link Map<String, WxMpConfigStorage>} 移除 {@link String label} 所对应的 {@link WxMpConfigStorage},适用于动态移除微信应用 * 从{@link Map<String, WxMpConfigStorage>} 移除 {@link String mpId} 所对应的 {@link WxMpConfigStorage},适用于动态移除微信公众号配置
* @param label * @param mpId 对应公众号的标识
*/ */
void removeWxMpConfigStorage(String label); void removeConfigStorage(String mpId);
/**
* 注入多个 {@link WxMpConfigStorage} 的实现. 并为每个 {@link WxMpConfigStorage} 赋予不同的 {@link String mpId} 值
* 随机采用一个{@link String mpId}进行Http初始化操作
* @param configStorages WxMpConfigStorage map
*/
void setMultiConfigStorages(Map<String, WxMpConfigStorage> configStorages);
/** /**
* 注入多个 {@link WxMpConfigStorage} 的实现. 并为每个 {@link WxMpConfigStorage} 赋予不同的 {@link String label} 值 * 注入多个 {@link WxMpConfigStorage} 的实现. 并为每个 {@link WxMpConfigStorage} 赋予不同的 {@link String label} 值
* 随机采用一个{@link String lable}进行Http初始化操作 * @param configStorages WxMpConfigStorage map
* @param configStorages * @param defaultMpId 设置一个{@link WxMpConfigStorage} 所对应的{@link String mpId}进行Http初始化
*/ */
void setMultiWxMpConfigStorage(Map<String, WxMpConfigStorage> configStorages); void setMultiConfigStorages(Map<String, WxMpConfigStorage> configStorages, String defaultMpId);
/** /**
* 注入多个 {@link WxMpConfigStorage} 的实现. 并为每个 {@link WxMpConfigStorage} 赋予不同的 {@link String label} 值 * 进行相应的公众号切换
* @param configStorages * @param mpId 公众号标识
* @param defaultInitLabel 设置一个{@link WxMpConfigStorage} 所对应的{@link String label}进行Http初始化 * @return 切换是否成功
*/ */
void setMultiWxMpConfigStorage(Map<String, WxMpConfigStorage> configStorages, String defaultInitLabel); boolean switchover(String mpId);
/** /**
* 进行相应的 WxApp 切换 * 进行相应的公众号切换
* @param label * @param mpId 公众号标识
* @return * @return 切换成功,则返回当前对象,方便链式调用,否则抛出异常
*/ */
boolean switchover(String label); WxMpService switchover1(String mpId);
/** /**
* 返回客服接口方法实现类,以方便调用其各个接口. * 返回客服接口方法实现类,以方便调用其各个接口.

View File

@ -1,15 +1,7 @@
package me.chanjar.weixin.mp.api.impl; package me.chanjar.weixin.mp.api.impl;
import java.io.IOException; import com.google.common.collect.ImmutableMap;
import java.util.HashMap; import com.google.common.collect.Maps;
import java.util.concurrent.locks.Lock;
import me.chanjar.weixin.mp.api.*;
import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
@ -23,14 +15,21 @@ import me.chanjar.weixin.common.util.DataUtils;
import me.chanjar.weixin.common.util.RandomUtils; import me.chanjar.weixin.common.util.RandomUtils;
import me.chanjar.weixin.common.util.crypto.SHA1; import me.chanjar.weixin.common.util.crypto.SHA1;
import me.chanjar.weixin.common.util.http.*; import me.chanjar.weixin.common.util.http.*;
import me.chanjar.weixin.mp.api.*;
import me.chanjar.weixin.mp.bean.WxMpSemanticQuery; import me.chanjar.weixin.mp.bean.WxMpSemanticQuery;
import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo; import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult; import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult;
import me.chanjar.weixin.mp.bean.result.WxMpUser; import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.enums.TicketType; import me.chanjar.weixin.mp.enums.TicketType;
import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Map; import java.util.Map;
import java.util.concurrent.locks.Lock;
/** /**
* 基础实现类. * 基础实现类.
@ -63,12 +62,11 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
private WxMpWifiService wifiService = new WxMpWifiServiceImpl(this); private WxMpWifiService wifiService = new WxMpWifiServiceImpl(this);
private WxMpMarketingService marketingService = new WxMpMarketingServiceImpl(this); private WxMpMarketingService marketingService = new WxMpMarketingServiceImpl(this);
private Map<String, WxMpConfigStorage> wxMpConfigStoragePool; private Map<String, WxMpConfigStorage> configStorageMap;
private int retrySleepMillis = 1000; private int retrySleepMillis = 1000;
private int maxRetryTimes = 5; private int maxRetryTimes = 5;
@Override @Override
public boolean checkSignature(String timestamp, String nonce, String signature) { public boolean checkSignature(String timestamp, String nonce, String signature) {
try { try {
@ -335,52 +333,62 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
@Override @Override
public WxMpConfigStorage getWxMpConfigStorage() { public WxMpConfigStorage getWxMpConfigStorage() {
return wxMpConfigStoragePool.get(WxMpConfigStorageHolder.get()); return this.configStorageMap.get(WxMpConfigStorageHolder.get());
} }
@Override @Override
public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) { public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) {
Map<String, WxMpConfigStorage> map = new HashMap<>(1); final String defaultMpId = WxMpConfigStorageHolder.get();
map.put(WxMpConfigStorageHolder.get(), wxConfigProvider); this.setMultiConfigStorages(ImmutableMap.of(defaultMpId, wxConfigProvider), defaultMpId);
setMultiWxMpConfigStorage(map, WxMpConfigStorageHolder.get());
} }
@Override @Override
public void setMultiWxMpConfigStorage(Map<String, WxMpConfigStorage> configStorages) { public void setMultiConfigStorages(Map<String, WxMpConfigStorage> configStorages) {
String randomKey = configStorages.keySet().iterator().next(); this.setMultiConfigStorages(configStorages, configStorages.keySet().iterator().next());
setMultiWxMpConfigStorage(configStorages, randomKey);
} }
@Override @Override
public void setMultiWxMpConfigStorage(Map<String, WxMpConfigStorage> configStorages, String defaultInitLabel) { public void setMultiConfigStorages(Map<String, WxMpConfigStorage> configStorages, String defaultMpId) {
wxMpConfigStoragePool = configStorages; this.configStorageMap = Maps.newHashMap(configStorages);
WxMpConfigStorageHolder.set(defaultInitLabel); WxMpConfigStorageHolder.set(defaultMpId);
this.initHttp(); this.initHttp();
} }
@Override @Override
public void addWxMpConfigStorage(String label, WxMpConfigStorage configStorages) { public void addConfigStorage(String mpId, WxMpConfigStorage configStorages) {
synchronized (this) { synchronized (this) {
if (wxMpConfigStoragePool.containsKey(label)) { if (this.configStorageMap.containsKey(mpId)) {
throw new RuntimeException("label已存在请重新设置一个label"); throw new RuntimeException("公众号标识已存在,请更换其他标识!");
} }
wxMpConfigStoragePool.put(label, configStorages); this.configStorageMap.put(mpId, configStorages);
} }
} }
@Override @Override
public void removeWxMpConfigStorage(String label) { public void removeConfigStorage(String mpId) {
synchronized (this) { synchronized (this) {
wxMpConfigStoragePool.remove(label); this.configStorageMap.remove(mpId);
} }
} }
@Override @Override
public boolean switchover(String label) { public WxMpService switchover1(String mpId) {
if (wxMpConfigStoragePool.containsKey(label)) { if (this.configStorageMap.containsKey(mpId)) {
WxMpConfigStorageHolder.set(label); WxMpConfigStorageHolder.set(mpId);
return this;
}
throw new RuntimeException(String.format("无法找到对应【%s】的公众号配置信息请核实", mpId));
}
@Override
public boolean switchover(String mpId) {
if (this.configStorageMap.containsKey(mpId)) {
WxMpConfigStorageHolder.set(mpId);
return true; return true;
} }
log.error("无法找到对应【{}】的公众号配置信息,请核实!", mpId);
return false; return false;
} }

View File

@ -0,0 +1,40 @@
package me.chanjar.weixin.mp.api.impl;
import com.google.inject.Inject;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.test.ApiTestModule;
import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
/**
* <pre>
* Created by BinaryWang on 2019/3/29.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@Test
@Guice(modules = ApiTestModule.class)
public class BaseWxMpServiceImplTest {
@Inject
private WxMpService wxService;
@Test
public void testSwitchover() {
assertTrue(this.wxService.switchover("another"));
assertThat(WxMpConfigStorageHolder.get()).isEqualTo("another");
assertFalse(this.wxService.switchover("whatever"));
}
@Test
public void testSwitchover1() throws WxErrorException {
assertThat(this.wxService.switchover1("another").getAccessToken()).isNotEmpty();
assertThat(WxMpConfigStorageHolder.get()).isEqualTo("another");
}
}

View File

@ -9,9 +9,11 @@ import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.test.ApiTestModule; import me.chanjar.weixin.mp.api.test.ApiTestModule;
import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult; import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult;
import me.chanjar.weixin.mp.bean.menu.WxMpMenu; import me.chanjar.weixin.mp.bean.menu.WxMpMenu;
import org.testng.annotations.*; import org.testng.annotations.DataProvider;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import static org.testng.Assert.*; import static org.testng.Assert.assertNotNull;
/** /**
* 测试菜单 * 测试菜单
@ -19,7 +21,7 @@ import static org.testng.Assert.*;
* @author chanjarster * @author chanjarster
* @author Binary Wang * @author Binary Wang
*/ */
@Test(groups = "menuAPI") @Test
@Guice(modules = ApiTestModule.class) @Guice(modules = ApiTestModule.class)
public class WxMpMenuServiceImplTest { public class WxMpMenuServiceImplTest {
@ -85,9 +87,6 @@ public class WxMpMenuServiceImplTest {
"}"; "}";
this.menuId = this.wxService.getMenuService().menuCreate(json); this.menuId = this.wxService.getMenuService().menuCreate(json);
if (this.wxService.switchover("test-1")) {
this.menuId = this.wxService.getMenuService().menuCreate(json);
}
System.out.println(this.menuId); System.out.println(this.menuId);
} }
@ -129,9 +128,7 @@ public class WxMpMenuServiceImplTest {
" \"language\":\"zh_CN\"\n" + " \"language\":\"zh_CN\"\n" +
" }\n" + " }\n" +
"}"; "}";
if (this.wxService.switchover("test-1")) { this.menuId = this.wxService.getMenuService().menuCreate(json);
this.menuId = this.wxService.getMenuService().menuCreate(json);
}
System.out.println(this.menuId); System.out.println(this.menuId);
} }
@ -194,7 +191,7 @@ public class WxMpMenuServiceImplTest {
System.out.println(wxMenu.toJson()); System.out.println(wxMenu.toJson());
} }
@Test(dependsOnMethods = {"testMenuGet","testMenuCreate"}) @Test(dependsOnMethods = {"testMenuGet", "testMenuCreate"})
public void testMenuDelete() throws WxErrorException { public void testMenuDelete() throws WxErrorException {
this.wxService.getMenuService().menuDelete(); this.wxService.getMenuService().menuDelete();
} }

View File

@ -2,8 +2,6 @@ package me.chanjar.weixin.mp.api.test;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import me.chanjar.weixin.mp.api.impl.WxMpServiceHttpClientImpl; import me.chanjar.weixin.mp.api.impl.WxMpServiceHttpClientImpl;
@ -16,7 +14,6 @@ import com.thoughtworks.xstream.XStream;
import me.chanjar.weixin.common.util.xml.XStreamInitializer; import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpConfigStorage;
import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceOkHttpImpl;
public class ApiTestModule implements Module { public class ApiTestModule implements Module {
private final Logger log = LoggerFactory.getLogger(this.getClass()); private final Logger log = LoggerFactory.getLogger(this.getClass());
@ -31,14 +28,13 @@ public class ApiTestModule implements Module {
TestConfigStorage config = this.fromXml(TestConfigStorage.class, inputStream); TestConfigStorage config = this.fromXml(TestConfigStorage.class, inputStream);
config.setAccessTokenLock(new ReentrantLock()); config.setAccessTokenLock(new ReentrantLock());
WxMpService wxMpServiceMulti = new WxMpServiceHttpClientImpl(); WxMpService mpService = new WxMpServiceHttpClientImpl();
// TODO 多WxAppId mpService.setWxMpConfigStorage(config);
wxMpServiceMulti.setWxMpConfigStorage(config); mpService.addConfigStorage("another", config);
wxMpServiceMulti.addWxMpConfigStorage("test-1", config);
binder.bind(WxMpConfigStorage.class).toInstance(config); binder.bind(WxMpConfigStorage.class).toInstance(config);
binder.bind(WxMpService.class).toInstance(wxMpServiceMulti); binder.bind(WxMpService.class).toInstance(mpService);
} catch (IOException e) { } catch (IOException e) {
this.log.error(e.getMessage(), e); this.log.error(e.getMessage(), e);
} }