mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-10-29 17:48:50 +08:00
优化多公众号支持代码
This commit is contained in:
@ -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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回客服接口方法实现类,以方便调用其各个接口.
|
* 返回客服接口方法实现类,以方便调用其各个接口.
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user