| @@ -12,7 +12,6 @@ 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 java.util.HashMap; | |||||
| import java.util.Map; | import java.util.Map; | ||||
| /** | /** | ||||
| @@ -309,12 +308,32 @@ public interface WxMpService { | |||||
| */ | */ | ||||
| void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider); | void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider); | ||||
| /** | |||||
| * {@link Map<String, WxMpConfigStorage>} 加入新的 {@link WxMpConfigStorage},适用于动态添加新的微信应用 | |||||
| * @param configStorages | |||||
| */ | |||||
| void addWxMpConfigStorage(String label, WxMpConfigStorage configStorages); | |||||
| /** | |||||
| * 从{@link Map<String, WxMpConfigStorage>} 移除 {@link String label} 所对应的 {@link WxMpConfigStorage},适用于动态移除的微信应用 | |||||
| * @param label | |||||
| */ | |||||
| void removeWxMpConfigStorage(String label); | |||||
| /** | /** | ||||
| * 注入多个 {@link WxMpConfigStorage} 的实现. 并为每个 {@link WxMpConfigStorage} 赋予不同的 {@link String label} 值 | * 注入多个 {@link WxMpConfigStorage} 的实现. 并为每个 {@link WxMpConfigStorage} 赋予不同的 {@link String label} 值 | ||||
| * @return | |||||
| * 随机采用一个{@link String lable}进行Http初始化操作 | |||||
| * @param configStorages | |||||
| */ | */ | ||||
| void setMultiWxMpConfigStorage(Map<String, WxMpConfigStorage> configStorages); | void setMultiWxMpConfigStorage(Map<String, WxMpConfigStorage> configStorages); | ||||
| /** | |||||
| * 注入多个 {@link WxMpConfigStorage} 的实现. 并为每个 {@link WxMpConfigStorage} 赋予不同的 {@link String label} 值 | |||||
| * @param configStorages | |||||
| * @param defaultInitLabel 设置一个{@link WxMpConfigStorage} 所对应的{@link String label}进行Http初始化 | |||||
| */ | |||||
| void setMultiWxMpConfigStorage(Map<String, WxMpConfigStorage> configStorages, String defaultInitLabel); | |||||
| /** | /** | ||||
| * 进行相应的 WxApp 切换 | * 进行相应的 WxApp 切换 | ||||
| * @param label | * @param label | ||||
| @@ -1,5 +1,15 @@ | |||||
| package me.chanjar.weixin.mp.api.impl; | package me.chanjar.weixin.mp.api.impl; | ||||
| import java.io.IOException; | |||||
| import java.util.HashMap; | |||||
| 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; | ||||
| @@ -13,21 +23,14 @@ 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; | |||||
| /** | /** | ||||
| * 基础实现类. | * 基础实现类. | ||||
| @@ -40,7 +43,6 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH | |||||
| protected final Logger log = LoggerFactory.getLogger(this.getClass()); | protected final Logger log = LoggerFactory.getLogger(this.getClass()); | ||||
| protected WxSessionManager sessionManager = new StandardSessionManager(); | protected WxSessionManager sessionManager = new StandardSessionManager(); | ||||
| protected WxMpConfigStorage wxMpConfigStorage; | |||||
| private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); | private WxMpKefuService kefuService = new WxMpKefuServiceImpl(this); | ||||
| private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); | private WxMpMaterialService materialService = new WxMpMaterialServiceImpl(this); | ||||
| private WxMpMenuService menuService = new WxMpMenuServiceImpl(this); | private WxMpMenuService menuService = new WxMpMenuServiceImpl(this); | ||||
| @@ -62,7 +64,6 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH | |||||
| private WxMpMarketingService marketingService = new WxMpMarketingServiceImpl(this); | private WxMpMarketingService marketingService = new WxMpMarketingServiceImpl(this); | ||||
| private Map<String, WxMpConfigStorage> wxMpConfigStoragePool; | private Map<String, WxMpConfigStorage> wxMpConfigStoragePool; | ||||
| private boolean isMultiWxApp = false; | |||||
| private int retrySleepMillis = 1000; | private int retrySleepMillis = 1000; | ||||
| private int maxRetryTimes = 5; | private int maxRetryTimes = 5; | ||||
| @@ -334,26 +335,46 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH | |||||
| @Override | @Override | ||||
| public WxMpConfigStorage getWxMpConfigStorage() { | public WxMpConfigStorage getWxMpConfigStorage() { | ||||
| if (isMultiWxApp) { | |||||
| return wxMpConfigStoragePool.get(WxMpConfigStorageHolder.get()); | |||||
| } | |||||
| return this.wxMpConfigStorage; | |||||
| return wxMpConfigStoragePool.get(WxMpConfigStorageHolder.get()); | |||||
| } | } | ||||
| @Override | @Override | ||||
| public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) { | public void setWxMpConfigStorage(WxMpConfigStorage wxConfigProvider) { | ||||
| this.wxMpConfigStorage = wxConfigProvider; | |||||
| this.initHttp(); | |||||
| Map<String, WxMpConfigStorage> map = new HashMap<>(1); | |||||
| map.put(WxMpConfigStorageHolder.get(), wxConfigProvider); | |||||
| setMultiWxMpConfigStorage(map, WxMpConfigStorageHolder.get()); | |||||
| } | } | ||||
| @Override | @Override | ||||
| public void setMultiWxMpConfigStorage(Map<String, WxMpConfigStorage> configStorages) { | public void setMultiWxMpConfigStorage(Map<String, WxMpConfigStorage> configStorages) { | ||||
| String randomKey = configStorages.keySet().iterator().next(); | |||||
| setMultiWxMpConfigStorage(configStorages, randomKey); | |||||
| } | |||||
| @Override | |||||
| public void setMultiWxMpConfigStorage(Map<String, WxMpConfigStorage> configStorages, String defaultInitLabel) { | |||||
| wxMpConfigStoragePool = configStorages; | wxMpConfigStoragePool = configStorages; | ||||
| isMultiWxApp = true; | |||||
| WxMpConfigStorageHolder.set(defaultInitLabel); | |||||
| this.initHttp(); | this.initHttp(); | ||||
| } | } | ||||
| @Override | |||||
| public void addWxMpConfigStorage(String label, WxMpConfigStorage configStorages) { | |||||
| synchronized (this) { | |||||
| if (wxMpConfigStoragePool.containsKey(label)) { | |||||
| throw new RuntimeException("该label已存在,请重新设置一个label"); | |||||
| } | |||||
| wxMpConfigStoragePool.put(label, configStorages); | |||||
| } | |||||
| } | |||||
| @Override | |||||
| public void removeWxMpConfigStorage(String label) { | |||||
| synchronized (this) { | |||||
| wxMpConfigStoragePool.remove(label); | |||||
| } | |||||
| } | |||||
| @Override | @Override | ||||
| public boolean switchover(String label) { | public boolean switchover(String label) { | ||||
| if (wxMpConfigStoragePool.containsKey(label)) { | if (wxMpConfigStoragePool.containsKey(label)) { | ||||
| @@ -6,6 +6,7 @@ import me.chanjar.weixin.common.error.WxError; | |||||
| import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.common.util.http.HttpType; | import me.chanjar.weixin.common.util.http.HttpType; | ||||
| import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; | import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; | ||||
| import me.chanjar.weixin.mp.api.WxMpConfigStorage; | |||||
| import me.chanjar.weixin.mp.api.WxMpService; | import me.chanjar.weixin.mp.api.WxMpService; | ||||
| import okhttp3.*; | import okhttp3.*; | ||||
| @@ -66,6 +67,7 @@ public class WxMpServiceOkHttpImpl extends BaseWxMpServiceImpl<OkHttpClient, OkH | |||||
| @Override | @Override | ||||
| public void initHttp() { | public void initHttp() { | ||||
| WxMpConfigStorage wxMpConfigStorage = getWxMpConfigStorage(); | |||||
| //设置代理 | //设置代理 | ||||
| if (wxMpConfigStorage.getHttpProxyHost() != null && wxMpConfigStorage.getHttpProxyPort() > 0) { | if (wxMpConfigStorage.getHttpProxyHost() != null && wxMpConfigStorage.getHttpProxyPort() > 0) { | ||||
| httpProxy = OkHttpProxyInfo.httpProxy(wxMpConfigStorage.getHttpProxyHost(), | httpProxy = OkHttpProxyInfo.httpProxy(wxMpConfigStorage.getHttpProxyHost(), | ||||
| @@ -7,7 +7,12 @@ package me.chanjar.weixin.mp.util; | |||||
| */ | */ | ||||
| public class WxMpConfigStorageHolder { | public class WxMpConfigStorageHolder { | ||||
| private final static ThreadLocal<String> WX_MP_CONFIG_STORAGE_CHOSE = new ThreadLocal<>(); | |||||
| private final static ThreadLocal<String> WX_MP_CONFIG_STORAGE_CHOSE = new ThreadLocal<String>() { | |||||
| @Override | |||||
| protected String initialValue() { | |||||
| return "default"; | |||||
| } | |||||
| }; | |||||
| public static String get() { | public static String get() { | ||||
| return WX_MP_CONFIG_STORAGE_CHOSE.get(); | return WX_MP_CONFIG_STORAGE_CHOSE.get(); | ||||
| @@ -85,6 +85,53 @@ 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); | |||||
| } | |||||
| @Test | |||||
| public void testMultiCreateConditionalMenu() throws WxErrorException { | |||||
| String json = "{\n" + | |||||
| " \"button\":[\n" + | |||||
| " { \n" + | |||||
| " \"type\":\"click\",\n" + | |||||
| " \"name\":\"今日歌曲\",\n" + | |||||
| " \"key\":\"V1001_TODAY_MUSIC\" \n" + | |||||
| " },\n" + | |||||
| " { \n" + | |||||
| " \"name\":\"菜单\",\n" + | |||||
| " \"sub_button\":[\n" + | |||||
| " { \n" + | |||||
| " \"type\":\"view\",\n" + | |||||
| " \"name\":\"搜索\",\n" + | |||||
| " \"url\":\"http://www.soso.com/\"\n" + | |||||
| " },\n" + | |||||
| " {\n" + | |||||
| " \"type\":\"view\",\n" + | |||||
| " \"name\":\"视频\",\n" + | |||||
| " \"url\":\"http://v.qq.com/\"\n" + | |||||
| " },\n" + | |||||
| " {\n" + | |||||
| " \"type\":\"click\",\n" + | |||||
| " \"name\":\"赞一下我们\",\n" + | |||||
| " \"key\":\"V1001_GOOD\"\n" + | |||||
| " }]\n" + | |||||
| " }],\n" + | |||||
| "\"matchrule\":{\n" + | |||||
| " \"tag_id\":\"2\",\n" + | |||||
| " \"sex\":\"1\",\n" + | |||||
| " \"country\":\"中国\",\n" + | |||||
| " \"province\":\"广东\",\n" + | |||||
| " \"city\":\"广州\",\n" + | |||||
| " \"client_platform_type\":\"2\",\n" + | |||||
| " \"language\":\"zh_CN\"\n" + | |||||
| " }\n" + | |||||
| "}"; | |||||
| if (this.wxService.switchover("test-1")) { | |||||
| this.menuId = this.wxService.getMenuService().menuCreate(json); | |||||
| } | |||||
| System.out.println(this.menuId); | System.out.println(this.menuId); | ||||
| } | } | ||||
| @@ -2,6 +2,8 @@ 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; | ||||
| @@ -29,11 +31,14 @@ 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 wxService = new WxMpServiceHttpClientImpl(); | |||||
| wxService.setWxMpConfigStorage(config); | |||||
| WxMpService wxMpServiceMulti = new WxMpServiceHttpClientImpl(); | |||||
| // TODO 多WxAppId | |||||
| wxMpServiceMulti.setWxMpConfigStorage(config); | |||||
| wxMpServiceMulti.addWxMpConfigStorage("test-1", config); | |||||
| binder.bind(WxMpService.class).toInstance(wxService); | |||||
| binder.bind(WxMpConfigStorage.class).toInstance(config); | binder.bind(WxMpConfigStorage.class).toInstance(config); | ||||
| binder.bind(WxMpService.class).toInstance(wxMpServiceMulti); | |||||
| } catch (IOException e) { | } catch (IOException e) { | ||||
| this.log.error(e.getMessage(), e); | this.log.error(e.getMessage(), e); | ||||
| } | } | ||||