Skip to content

Commit 4262128

Browse files
authored
🆕 添加 solon-plugins 下的两个新模块
1 parent 17399b5 commit 4262128

36 files changed

+1737
-11
lines changed

solon-plugins/pom.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414
<description>WxJava 各个模块的 Solon Plugin</description>
1515

1616
<properties>
17-
<solon.version>2.9.2</solon.version>
17+
<solon.version>3.0.1</solon.version>
1818
</properties>
1919

2020
<modules>
21+
<module>wx-java-miniapp-multi-solon-plugin</module>
2122
<module>wx-java-miniapp-solon-plugin</module>
2223
<module>wx-java-mp-multi-solon-plugin</module>
2324
<module>wx-java-mp-solon-plugin</module>
@@ -27,6 +28,7 @@
2728
<module>wx-java-cp-multi-solon-plugin</module>
2829
<module>wx-java-cp-solon-plugin</module>
2930
<module>wx-java-channel-solon-plugin</module>
31+
<module>wx-java-channel-multi-solon-plugin</module>
3032
</modules>
3133

3234
<dependencies>
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# wx-java-channel-multi-solon-plugin
2+
3+
## 快速开始
4+
5+
1. 引入依赖
6+
```xml
7+
<dependencies>
8+
<dependency>
9+
<groupId>com.github.binarywang</groupId>
10+
<artifactId>wx-java-channel-multi-solon-plugin</artifactId>
11+
<version>${version}</version>
12+
</dependency>
13+
14+
<!-- 配置存储方式为jedis 则引入jedis -->
15+
<dependency>
16+
<groupId>redis.clients</groupId>
17+
<artifactId>jedis</artifactId>
18+
<version>${jedis.version}</version>
19+
</dependency>
20+
21+
<!-- 配置存储方式为redisson 则引入redisson -->
22+
<dependency>
23+
<groupId>org.redisson</groupId>
24+
<artifactId>redisson</artifactId>
25+
<version>${redisson.version}</version>
26+
</dependency>
27+
</dependencies>
28+
```
29+
2. 添加配置(app.properties)
30+
```properties
31+
# 视频号配置
32+
## 应用 1 配置(必填)
33+
wx.channel.apps.tenantId1.app-id=@appId
34+
wx.channel.apps.tenantId1.secret=@secret
35+
## 选填
36+
wx.channel.apps.tenantId1.use-stable-access-token=false
37+
wx.channel.apps.tenantId1.token=
38+
wx.channel.apps.tenantId1.aes-key=
39+
## 应用 2 配置(必填)
40+
wx.channel.apps.tenantId2.app-id=@appId
41+
wx.channel.apps.tenantId2.secret=@secret
42+
## 选填
43+
wx.channel.apps.tenantId2.use-stable-access-token=false
44+
wx.channel.apps.tenantId2.token=
45+
wx.channel.apps.tenantId2.aes-key=
46+
47+
# ConfigStorage 配置(选填)
48+
## 配置类型: memory(默认), jedis, redisson, redis_template
49+
wx.channel.config-storage.type=memory
50+
## 相关redis前缀配置: wx:channel:multi(默认)
51+
wx.channel.config-storage.key-prefix=wx:channel:multi
52+
wx.channel.config-storage.redis.host=127.0.0.1
53+
wx.channel.config-storage.redis.port=6379
54+
wx.channel.config-storage.redis.password=123456
55+
56+
# http 客户端配置(选填)
57+
## # http客户端类型: http_client(默认)
58+
wx.channel.config-storage.http-client-type=http_client
59+
wx.channel.config-storage.http-proxy-host=
60+
wx.channel.config-storage.http-proxy-port=
61+
wx.channel.config-storage.http-proxy-username=
62+
wx.channel.config-storage.http-proxy-password=
63+
## 最大重试次数,默认:5 次,如果小于 0,则为 0
64+
wx.channel.config-storage.max-retry-times=5
65+
## 重试时间间隔步进,默认:1000 毫秒,如果小于 0,则为 1000
66+
wx.channel.config-storage.retry-sleep-millis=1000
67+
```
68+
3. 自动注入的类型:`WxChannelMultiServices`
69+
70+
4. 使用样例
71+
72+
```java
73+
import com.binarywang.solon.wxjava.channel.service.WxChannelMultiServices;
74+
import me.chanjar.weixin.channel.api.WxChannelService;
75+
import me.chanjar.weixin.channel.api.WxFinderLiveService;
76+
import me.chanjar.weixin.channel.bean.lead.component.response.FinderAttrResponse;
77+
import me.chanjar.weixin.common.error.WxErrorException;
78+
import org.noear.solon.annotation.Component;
79+
import org.noear.solon.annotation.Inject;
80+
81+
@Component
82+
public class DemoService {
83+
@Inject
84+
private WxChannelMultiServices wxChannelMultiServices;
85+
86+
public void test() throws WxErrorException {
87+
// 应用 1 的 WxChannelService
88+
WxChannelService wxChannelService1 = wxChannelMultiServices.getWxChannelService("tenantId1");
89+
WxFinderLiveService finderLiveService = wxChannelService1.getFinderLiveService();
90+
FinderAttrResponse response1 = finderLiveService.getFinderAttrByAppid();
91+
// todo ...
92+
93+
// 应用 2 的 WxChannelService
94+
WxChannelService wxChannelService2 = wxChannelMultiServices.getWxChannelService("tenantId2");
95+
WxFinderLiveService finderLiveService2 = wxChannelService2.getFinderLiveService();
96+
FinderAttrResponse response2 = finderLiveService2.getFinderAttrByAppid();
97+
// todo ...
98+
99+
// 应用 3 的 WxChannelService
100+
WxChannelService wxChannelService3 = wxChannelMultiServices.getWxChannelService("tenantId3");
101+
// 判断是否为空
102+
if (wxChannelService3 == null) {
103+
// todo wxChannelService3 为空,请先配置 tenantId3 微信视频号应用参数
104+
return;
105+
}
106+
WxFinderLiveService finderLiveService3 = wxChannelService3.getFinderLiveService();
107+
FinderAttrResponse response3 = finderLiveService3.getFinderAttrByAppid();
108+
// todo ...
109+
}
110+
}
111+
```
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>wx-java-solon-plugins</artifactId>
7+
<groupId>com.github.binarywang</groupId>
8+
<version>4.6.5.B</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>wx-java-channel-multi-solon-plugin</artifactId>
13+
<name>WxJava - Solon Plugin for Channel::支持多账号配置</name>
14+
<description>微信视频号开发的 Solon Plugin::支持多账号配置</description>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>com.github.binarywang</groupId>
19+
<artifactId>weixin-java-channel</artifactId>
20+
<version>${project.version}</version>
21+
</dependency>
22+
<dependency>
23+
<groupId>redis.clients</groupId>
24+
<artifactId>jedis</artifactId>
25+
<scope>provided</scope>
26+
</dependency>
27+
<dependency>
28+
<groupId>org.redisson</groupId>
29+
<artifactId>redisson</artifactId>
30+
<scope>provided</scope>
31+
</dependency>
32+
<dependency>
33+
<groupId>org.jodd</groupId>
34+
<artifactId>jodd-http</artifactId>
35+
<scope>provided</scope>
36+
</dependency>
37+
<dependency>
38+
<groupId>com.squareup.okhttp3</groupId>
39+
<artifactId>okhttp</artifactId>
40+
<scope>provided</scope>
41+
</dependency>
42+
</dependencies>
43+
</project>
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package com.binarywang.solon.wxjava.channel.configuration.services;
2+
3+
import com.binarywang.solon.wxjava.channel.enums.HttpClientType;
4+
import com.binarywang.solon.wxjava.channel.properties.WxChannelMultiProperties;
5+
import com.binarywang.solon.wxjava.channel.properties.WxChannelSingleProperties;
6+
import com.binarywang.solon.wxjava.channel.service.WxChannelMultiServices;
7+
import com.binarywang.solon.wxjava.channel.service.WxChannelMultiServicesImpl;
8+
import lombok.RequiredArgsConstructor;
9+
import lombok.extern.slf4j.Slf4j;
10+
import me.chanjar.weixin.channel.api.WxChannelService;
11+
import me.chanjar.weixin.channel.api.impl.WxChannelServiceHttpClientImpl;
12+
import me.chanjar.weixin.channel.api.impl.WxChannelServiceImpl;
13+
import me.chanjar.weixin.channel.config.WxChannelConfig;
14+
import me.chanjar.weixin.channel.config.impl.WxChannelDefaultConfigImpl;
15+
import org.apache.commons.lang3.StringUtils;
16+
17+
import java.util.Collection;
18+
import java.util.Map;
19+
import java.util.Set;
20+
import java.util.stream.Collectors;
21+
22+
/**
23+
* WxChannelConfigStorage 抽象配置类
24+
*
25+
* @author <a href="https://github.com/Winnie-by996">Winnie</a> 2024/9/13
26+
* @author noear
27+
*/
28+
@RequiredArgsConstructor
29+
@Slf4j
30+
public abstract class AbstractWxChannelConfiguration {
31+
protected WxChannelMultiServices wxChannelMultiServices(WxChannelMultiProperties wxChannelMultiProperties) {
32+
Map<String, WxChannelSingleProperties> appsMap = wxChannelMultiProperties.getApps();
33+
if (appsMap == null || appsMap.isEmpty()) {
34+
log.warn("微信视频号应用参数未配置,通过 WxChannelMultiServices#getWxChannelService(\"tenantId\")获取实例将返回空");
35+
return new WxChannelMultiServicesImpl();
36+
}
37+
/**
38+
* 校验 appId 是否唯一,避免使用 redis 缓存 token、ticket 时错乱。
39+
*
40+
* 查看 {@link me.chanjar.weixin.channel.config.impl.WxChannelRedisConfigImpl#setAppid(String)}
41+
*/
42+
Collection<WxChannelSingleProperties> apps = appsMap.values();
43+
if (apps.size() > 1) {
44+
// 校验 appId 是否唯一
45+
boolean multi = apps.stream()
46+
// 没有 appId,如果不判断是否为空,这里会报 NPE 异常
47+
.collect(Collectors.groupingBy(c -> c.getAppId() == null ? 0 : c.getAppId(), Collectors.counting()))
48+
.entrySet().stream().anyMatch(e -> e.getValue() > 1);
49+
if (multi) {
50+
throw new RuntimeException("请确保微信视频号配置 appId 的唯一性");
51+
}
52+
}
53+
WxChannelMultiServicesImpl services = new WxChannelMultiServicesImpl();
54+
55+
Set<Map.Entry<String, WxChannelSingleProperties>> entries = appsMap.entrySet();
56+
for (Map.Entry<String, WxChannelSingleProperties> entry : entries) {
57+
String tenantId = entry.getKey();
58+
WxChannelSingleProperties wxChannelSingleProperties = entry.getValue();
59+
WxChannelDefaultConfigImpl storage = this.wxChannelConfigStorage(wxChannelMultiProperties);
60+
this.configApp(storage, wxChannelSingleProperties);
61+
this.configHttp(storage, wxChannelMultiProperties.getConfigStorage());
62+
WxChannelService wxChannelService = this.wxChannelService(storage, wxChannelMultiProperties, wxChannelSingleProperties.isUseStableAccessToken());
63+
services.addWxChannelService(tenantId, wxChannelService);
64+
}
65+
return services;
66+
}
67+
68+
/**
69+
* 配置 WxChannelDefaultConfigImpl
70+
*
71+
* @param wxChannelMultiProperties 参数
72+
* @return WxChannelDefaultConfigImpl
73+
*/
74+
protected abstract WxChannelDefaultConfigImpl wxChannelConfigStorage(WxChannelMultiProperties wxChannelMultiProperties);
75+
76+
public WxChannelService wxChannelService(WxChannelConfig wxChannelConfig, WxChannelMultiProperties wxChannelMultiProperties, boolean useStableAccessToken) {
77+
WxChannelMultiProperties.ConfigStorage storage = wxChannelMultiProperties.getConfigStorage();
78+
HttpClientType httpClientType = storage.getHttpClientType();
79+
WxChannelService wxChannelService;
80+
switch (httpClientType) {
81+
// case OK_HTTP:
82+
// wxChannelService = new WxChannelServiceOkHttpImpl(false, false);
83+
// break;
84+
case HTTP_CLIENT:
85+
wxChannelService = new WxChannelServiceHttpClientImpl(useStableAccessToken, false);
86+
break;
87+
default:
88+
wxChannelService = new WxChannelServiceImpl();
89+
break;
90+
}
91+
92+
wxChannelService.setConfig(wxChannelConfig);
93+
int maxRetryTimes = storage.getMaxRetryTimes();
94+
if (maxRetryTimes < 0) {
95+
maxRetryTimes = 0;
96+
}
97+
int retrySleepMillis = storage.getRetrySleepMillis();
98+
if (retrySleepMillis < 0) {
99+
retrySleepMillis = 1000;
100+
}
101+
wxChannelService.setRetrySleepMillis(retrySleepMillis);
102+
wxChannelService.setMaxRetryTimes(maxRetryTimes);
103+
return wxChannelService;
104+
}
105+
106+
private void configApp(WxChannelDefaultConfigImpl config, WxChannelSingleProperties wxChannelSingleProperties) {
107+
String appId = wxChannelSingleProperties.getAppId();
108+
String appSecret = wxChannelSingleProperties.getSecret();
109+
String token = wxChannelSingleProperties.getToken();
110+
String aesKey = wxChannelSingleProperties.getAesKey();
111+
112+
config.setAppid(appId);
113+
config.setSecret(appSecret);
114+
if (StringUtils.isNotBlank(token)) {
115+
config.setToken(token);
116+
}
117+
if (StringUtils.isNotBlank(aesKey)) {
118+
config.setAesKey(aesKey);
119+
}
120+
}
121+
122+
private void configHttp(WxChannelDefaultConfigImpl config, WxChannelMultiProperties.ConfigStorage storage) {
123+
String httpProxyHost = storage.getHttpProxyHost();
124+
Integer httpProxyPort = storage.getHttpProxyPort();
125+
String httpProxyUsername = storage.getHttpProxyUsername();
126+
String httpProxyPassword = storage.getHttpProxyPassword();
127+
if (StringUtils.isNotBlank(httpProxyHost)) {
128+
config.setHttpProxyHost(httpProxyHost);
129+
if (httpProxyPort != null) {
130+
config.setHttpProxyPort(httpProxyPort);
131+
}
132+
if (StringUtils.isNotBlank(httpProxyUsername)) {
133+
config.setHttpProxyUsername(httpProxyUsername);
134+
}
135+
if (StringUtils.isNotBlank(httpProxyPassword)) {
136+
config.setHttpProxyPassword(httpProxyPassword);
137+
}
138+
}
139+
}
140+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.binarywang.solon.wxjava.channel.configuration.services;
2+
3+
import com.binarywang.solon.wxjava.channel.properties.WxChannelMultiProperties;
4+
import com.binarywang.solon.wxjava.channel.properties.WxChannelMultiRedisProperties;
5+
import com.binarywang.solon.wxjava.channel.service.WxChannelMultiServices;
6+
import lombok.RequiredArgsConstructor;
7+
import me.chanjar.weixin.channel.config.impl.WxChannelDefaultConfigImpl;
8+
import me.chanjar.weixin.channel.config.impl.WxChannelRedisConfigImpl;
9+
import me.chanjar.weixin.common.redis.JedisWxRedisOps;
10+
import org.apache.commons.lang3.StringUtils;
11+
import org.noear.solon.annotation.Bean;
12+
import org.noear.solon.annotation.Condition;
13+
import org.noear.solon.annotation.Configuration;
14+
import org.noear.solon.core.AppContext;
15+
import redis.clients.jedis.JedisPool;
16+
import redis.clients.jedis.JedisPoolConfig;
17+
18+
/**
19+
* 自动装配基于 jedis 策略配置
20+
*
21+
* @author <a href="https://github.com/Winnie-by996">Winnie</a> 2024/9/13
22+
* @author noear
23+
*/
24+
@Configuration
25+
@Condition(
26+
onProperty = "${"+WxChannelMultiProperties.PREFIX + ".configStorage.type} = jedis",
27+
onClass = JedisPool.class
28+
)
29+
@RequiredArgsConstructor
30+
public class WxChannelInJedisConfiguration extends AbstractWxChannelConfiguration {
31+
private final WxChannelMultiProperties wxChannelMultiProperties;
32+
private final AppContext applicationContext;
33+
34+
@Bean
35+
public WxChannelMultiServices wxChannelMultiServices() {
36+
return this.wxChannelMultiServices(wxChannelMultiProperties);
37+
}
38+
39+
@Override
40+
protected WxChannelDefaultConfigImpl wxChannelConfigStorage(WxChannelMultiProperties wxChannelMultiProperties) {
41+
return this.configRedis(wxChannelMultiProperties);
42+
}
43+
44+
private WxChannelDefaultConfigImpl configRedis(WxChannelMultiProperties wxChannelMultiProperties) {
45+
WxChannelMultiRedisProperties wxChannelMultiRedisProperties = wxChannelMultiProperties.getConfigStorage().getRedis();
46+
JedisPool jedisPool;
47+
if (wxChannelMultiRedisProperties != null && StringUtils.isNotEmpty(wxChannelMultiRedisProperties.getHost())) {
48+
jedisPool = getJedisPool(wxChannelMultiProperties);
49+
} else {
50+
jedisPool = applicationContext.getBean(JedisPool.class);
51+
}
52+
return new WxChannelRedisConfigImpl(new JedisWxRedisOps(jedisPool), wxChannelMultiProperties.getConfigStorage().getKeyPrefix());
53+
}
54+
55+
private JedisPool getJedisPool(WxChannelMultiProperties wxChannelMultiProperties) {
56+
WxChannelMultiProperties.ConfigStorage storage = wxChannelMultiProperties.getConfigStorage();
57+
WxChannelMultiRedisProperties redis = storage.getRedis();
58+
59+
JedisPoolConfig config = new JedisPoolConfig();
60+
if (redis.getMaxActive() != null) {
61+
config.setMaxTotal(redis.getMaxActive());
62+
}
63+
if (redis.getMaxIdle() != null) {
64+
config.setMaxIdle(redis.getMaxIdle());
65+
}
66+
if (redis.getMaxWaitMillis() != null) {
67+
config.setMaxWaitMillis(redis.getMaxWaitMillis());
68+
}
69+
if (redis.getMinIdle() != null) {
70+
config.setMinIdle(redis.getMinIdle());
71+
}
72+
config.setTestOnBorrow(true);
73+
config.setTestWhileIdle(true);
74+
75+
return new JedisPool(config, redis.getHost(), redis.getPort(), redis.getTimeout(), redis.getPassword(), redis.getDatabase());
76+
}
77+
}

0 commit comments

Comments
 (0)