Skip to content

Commit 88bdd4a

Browse files
🆕 #3703 【企业微信】第三方应用基础接口实现
1 parent 213cf6f commit 88bdd4a

35 files changed

+1730
-492
lines changed

pom.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,21 @@
468468
</execution>
469469
</executions>
470470
</plugin>
471+
<plugin>
472+
<groupId>org.apache.maven.plugins</groupId>
473+
<artifactId>maven-source-plugin</artifactId>
474+
<version>3.3.0</version> <!-- 建议使用最新版本 -->
475+
<executions>
476+
<execution>
477+
<id>attach-sources</id>
478+
<!-- 绑定到 verify 阶段,在 install 之前执行 -->
479+
<phase>verify</phase>
480+
<goals>
481+
<goal>jar-no-fork</goal> <!-- 使用 jar-no-fork 效率更高 -->
482+
</goals>
483+
</execution>
484+
</executions>
485+
</plugin>
471486
</plugins>
472487
</build>
473488

spring-boot-starters/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
<module>wx-java-open-spring-boot-starter</module>
2727
<module>wx-java-qidian-spring-boot-starter</module>
2828
<module>wx-java-cp-multi-spring-boot-starter</module>
29+
<module>wx-java-cp-tp-multi-spring-boot-starter</module>
2930
<module>wx-java-cp-spring-boot-starter</module>
3031
<module>wx-java-channel-spring-boot-starter</module>
3132
<module>wx-java-channel-multi-spring-boot-starter</module>
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# wx-java-cp-multi-spring-boot-starter
2+
3+
企业微信多账号配置
4+
5+
- 实现多 WxCpService 初始化。
6+
- 未实现 WxCpTpService 初始化,需要的小伙伴可以参考多 WxCpService 配置的实现。
7+
- 未实现 WxCpCgService 初始化,需要的小伙伴可以参考多 WxCpService 配置的实现。
8+
9+
## 快速开始
10+
11+
1. 引入依赖
12+
```xml
13+
<dependency>
14+
<groupId>com.github.binarywang</groupId>
15+
<artifactId>wx-java-cp-multi-spring-boot-starter</artifactId>
16+
<version>${version}</version>
17+
</dependency>
18+
```
19+
2. 添加配置(application.properties)
20+
```properties
21+
# 应用 1 配置
22+
wx.cp.corps.tenantId1.corp-id = @corp-id
23+
wx.cp.corps.tenantId1.corp-secret = @corp-secret
24+
## 选填
25+
wx.cp.corps.tenantId1.agent-id = @agent-id
26+
wx.cp.corps.tenantId1.token = @token
27+
wx.cp.corps.tenantId1.aes-key = @aes-key
28+
wx.cp.corps.tenantId1.msg-audit-priKey = @msg-audit-priKey
29+
wx.cp.corps.tenantId1.msg-audit-lib-path = @msg-audit-lib-path
30+
31+
# 应用 2 配置
32+
wx.cp.corps.tenantId2.corp-id = @corp-id
33+
wx.cp.corps.tenantId2.corp-secret = @corp-secret
34+
## 选填
35+
wx.cp.corps.tenantId2.agent-id = @agent-id
36+
wx.cp.corps.tenantId2.token = @token
37+
wx.cp.corps.tenantId2.aes-key = @aes-key
38+
wx.cp.corps.tenantId2.msg-audit-priKey = @msg-audit-priKey
39+
wx.cp.corps.tenantId2.msg-audit-lib-path = @msg-audit-lib-path
40+
41+
# 公共配置
42+
## ConfigStorage 配置(选填)
43+
wx.cp.config-storage.type=memory # 配置类型: memory(默认), jedis, redisson, redistemplate
44+
## http 客户端配置(选填)
45+
## # http客户端类型: http_client(默认), ok_http, jodd_http
46+
wx.cp.config-storage.http-client-type=http_client
47+
wx.cp.config-storage.http-proxy-host=
48+
wx.cp.config-storage.http-proxy-port=
49+
wx.cp.config-storage.http-proxy-username=
50+
wx.cp.config-storage.http-proxy-password=
51+
## 最大重试次数,默认:5 次,如果小于 0,则为 0
52+
wx.cp.config-storage.max-retry-times=5
53+
## 重试时间间隔步进,默认:1000 毫秒,如果小于 0,则为 1000
54+
wx.cp.config-storage.retry-sleep-millis=1000
55+
```
56+
3. 支持自动注入的类型: `WxCpMultiServices`
57+
58+
4. 使用样例
59+
60+
```java
61+
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServices;
62+
import me.chanjar.weixin.cp.api.WxCpService;
63+
import me.chanjar.weixin.cp.api.WxCpUserService;
64+
import org.springframework.beans.factory.annotation.Autowired;
65+
import org.springframework.stereotype.Service;
66+
67+
@Service
68+
public class DemoService {
69+
@Autowired
70+
private WxCpTpMultiServices wxCpTpMultiServices;
71+
72+
public void test() {
73+
// 应用 1 的 WxCpService
74+
WxCpService wxCpService1 = wxCpMultiServices.getWxCpService("tenantId1");
75+
WxCpUserService userService1 = wxCpService1.getUserService();
76+
userService1.getUserId("xxx");
77+
// todo ...
78+
79+
// 应用 2 的 WxCpService
80+
WxCpService wxCpService2 = wxCpMultiServices.getWxCpService("tenantId2");
81+
WxCpUserService userService2 = wxCpService2.getUserService();
82+
userService2.getUserId("xxx");
83+
// todo ...
84+
85+
// 应用 3 的 WxCpService
86+
WxCpService wxCpService3 = wxCpMultiServices.getWxCpService("tenantId3");
87+
// 判断是否为空
88+
if (wxCpService3 == null) {
89+
// todo wxCpService3 为空,请先配置 tenantId3 企业微信应用参数
90+
return;
91+
}
92+
WxCpUserService userService3 = wxCpService3.getUserService();
93+
userService3.getUserId("xxx");
94+
// todo ...
95+
}
96+
}
97+
```
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<parent>
5+
<artifactId>wx-java-spring-boot-starters</artifactId>
6+
<groupId>com.github.binarywang</groupId>
7+
<version>4.7.7.B</version>
8+
</parent>
9+
<modelVersion>4.0.0</modelVersion>
10+
11+
<artifactId>wx-java-cp-tp-multi-spring-boot-starter</artifactId>
12+
<name>WxJava - Spring Boot Starter for WxCp::支持多账号配置</name>
13+
<description>微信企业号开发的 Spring Boot Starter::支持多账号配置</description>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>com.github.binarywang</groupId>
18+
<artifactId>weixin-java-cp</artifactId>
19+
<version>${project.version}</version>
20+
</dependency>
21+
<dependency>
22+
<groupId>redis.clients</groupId>
23+
<artifactId>jedis</artifactId>
24+
<scope>provided</scope>
25+
</dependency>
26+
<dependency>
27+
<groupId>org.redisson</groupId>
28+
<artifactId>redisson</artifactId>
29+
<scope>provided</scope>
30+
</dependency>
31+
<dependency>
32+
<groupId>org.springframework.data</groupId>
33+
<artifactId>spring-data-redis</artifactId>
34+
<scope>provided</scope>
35+
</dependency>
36+
</dependencies>
37+
38+
<build>
39+
<plugins>
40+
<plugin>
41+
<groupId>org.springframework.boot</groupId>
42+
<artifactId>spring-boot-maven-plugin</artifactId>
43+
<version>${spring.boot.version}</version>
44+
</plugin>
45+
<plugin>
46+
<groupId>org.apache.maven.plugins</groupId>
47+
<artifactId>maven-source-plugin</artifactId>
48+
<version>2.2.1</version>
49+
<executions>
50+
<execution>
51+
<id>attach-sources</id>
52+
<goals>
53+
<goal>jar-no-fork</goal>
54+
</goals>
55+
</execution>
56+
</executions>
57+
</plugin>
58+
</plugins>
59+
</build>
60+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.binarywang.spring.starter.wxjava.cp.autoconfigure;
2+
3+
import com.binarywang.spring.starter.wxjava.cp.configuration.WxCpTpMultiServicesAutoConfiguration;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.context.annotation.Import;
6+
7+
/**
8+
* 企业微信自动注册
9+
*
10+
* @author yl
11+
* created on 2023/10/16
12+
*/
13+
@Configuration
14+
@Import(WxCpTpMultiServicesAutoConfiguration.class)
15+
public class WxCpTpMultiAutoConfiguration {
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.binarywang.spring.starter.wxjava.cp.configuration;
2+
3+
import com.binarywang.spring.starter.wxjava.cp.configuration.services.WxCpTpInJedisTpConfiguration;
4+
import com.binarywang.spring.starter.wxjava.cp.configuration.services.WxCpTpInMemoryTpConfiguration;
5+
import com.binarywang.spring.starter.wxjava.cp.configuration.services.WxCpTpInRedisTemplateTpConfiguration;
6+
import com.binarywang.spring.starter.wxjava.cp.configuration.services.WxCpTpInRedissonTpConfiguration;
7+
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiProperties;
8+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
9+
import org.springframework.context.annotation.Configuration;
10+
import org.springframework.context.annotation.Import;
11+
12+
/**
13+
* 企业微信平台相关服务自动注册
14+
*
15+
* @author yl
16+
* created on 2023/10/16
17+
*/
18+
@Configuration
19+
@EnableConfigurationProperties(WxCpTpMultiProperties.class)
20+
@Import({
21+
WxCpTpInJedisTpConfiguration.class,
22+
WxCpTpInMemoryTpConfiguration.class,
23+
WxCpTpInRedissonTpConfiguration.class,
24+
WxCpTpInRedisTemplateTpConfiguration.class
25+
})
26+
public class WxCpTpMultiServicesAutoConfiguration {
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package com.binarywang.spring.starter.wxjava.cp.configuration.services;
2+
3+
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiProperties;
4+
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpSingleProperties;
5+
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServices;
6+
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServicesImpl;
7+
import lombok.RequiredArgsConstructor;
8+
import lombok.extern.slf4j.Slf4j;
9+
import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
10+
import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl;
11+
import me.chanjar.weixin.cp.tp.service.WxCpTpService;
12+
import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceApacheHttpClientImpl;
13+
import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceImpl;
14+
import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceJoddHttpImpl;
15+
import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceOkHttpImpl;
16+
import org.apache.commons.lang3.StringUtils;
17+
18+
import java.util.Collection;
19+
import java.util.List;
20+
import java.util.Map;
21+
import java.util.Set;
22+
import java.util.stream.Collectors;
23+
24+
/**
25+
* WxCpConfigStorage 抽象配置类
26+
*
27+
* @author yl
28+
* created on 2023/10/16
29+
*/
30+
@RequiredArgsConstructor
31+
@Slf4j
32+
public abstract class AbstractWxCpTpConfiguration {
33+
34+
/**
35+
*
36+
* @param wxCpTpMultiProperties 应用列表配置
37+
* @param services 用于支持,应用启动之后,可以调用这个接口添加新服务对象。主要是配置是从数据库中读取的
38+
* @return
39+
*/
40+
public WxCpTpMultiServices wxCpMultiServices(WxCpTpMultiProperties wxCpTpMultiProperties,WxCpTpMultiServices services) {
41+
Map<String, WxCpTpSingleProperties> corps = wxCpTpMultiProperties.getCorps();
42+
if (corps == null || corps.isEmpty()) {
43+
log.warn("企业微信应用参数未配置,通过 WxCpMultiServices#getWxCpTpService(\"tenantId\")获取实例将返回空");
44+
return new WxCpTpMultiServicesImpl();
45+
}
46+
47+
if (services == null) {
48+
services = new WxCpTpMultiServicesImpl();
49+
}
50+
51+
Set<Map.Entry<String, WxCpTpSingleProperties>> entries = corps.entrySet();
52+
for (Map.Entry<String, WxCpTpSingleProperties> entry : entries) {
53+
String tenantId = entry.getKey();
54+
WxCpTpSingleProperties wxCpTpSingleProperties = entry.getValue();
55+
WxCpTpDefaultConfigImpl storage = this.wxCpTpConfigStorage(wxCpTpMultiProperties);
56+
this.configCorp(storage, wxCpTpSingleProperties);
57+
this.configHttp(storage, wxCpTpMultiProperties.getConfigStorage());
58+
WxCpTpService wxCpTpService = this.wxCpTpService(storage, wxCpTpMultiProperties.getConfigStorage());
59+
if (services.getWxCpTpService(tenantId) == null) {
60+
// 不存在的才会添加到服务列表中
61+
services.addWxCpTpService(tenantId, wxCpTpService);
62+
}
63+
}
64+
return services;
65+
}
66+
67+
/**
68+
* 配置 WxCpDefaultConfigImpl
69+
*
70+
* @param wxCpTpMultiProperties 参数
71+
* @return WxCpDefaultConfigImpl
72+
*/
73+
protected abstract WxCpTpDefaultConfigImpl wxCpTpConfigStorage(WxCpTpMultiProperties wxCpTpMultiProperties);
74+
75+
private WxCpTpService wxCpTpService(WxCpTpConfigStorage wxCpTpConfigStorage, WxCpTpMultiProperties.ConfigStorage storage) {
76+
WxCpTpMultiProperties.HttpClientType httpClientType = storage.getHttpClientType();
77+
WxCpTpService cpTpService;
78+
switch (httpClientType) {
79+
case OK_HTTP:
80+
cpTpService = new WxCpTpServiceOkHttpImpl();
81+
break;
82+
case JODD_HTTP:
83+
cpTpService = new WxCpTpServiceJoddHttpImpl();
84+
break;
85+
case HTTP_CLIENT:
86+
cpTpService = new WxCpTpServiceApacheHttpClientImpl();
87+
break;
88+
default:
89+
cpTpService = new WxCpTpServiceImpl();
90+
break;
91+
}
92+
cpTpService.setWxCpTpConfigStorage(wxCpTpConfigStorage);
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+
cpTpService.setRetrySleepMillis(retrySleepMillis);
102+
cpTpService.setMaxRetryTimes(maxRetryTimes);
103+
return cpTpService;
104+
}
105+
106+
private void configCorp(WxCpTpDefaultConfigImpl config, WxCpTpSingleProperties wxCpTpSingleProperties) {
107+
String corpId = wxCpTpSingleProperties.getCorpId();
108+
String providerSecret = wxCpTpSingleProperties.getProviderSecret();
109+
String suiteId = wxCpTpSingleProperties.getSuiteId();
110+
String token = wxCpTpSingleProperties.getToken();
111+
String suiteSecret = wxCpTpSingleProperties.getSuiteSecret();
112+
// 企业微信,私钥,会话存档路径
113+
config.setCorpId(corpId);
114+
config.setProviderSecret(providerSecret);
115+
config.setEncodingAESKey(wxCpTpSingleProperties.getEncodingAESKey());
116+
config.setSuiteId(suiteId);
117+
config.setToken(token);
118+
config.setSuiteSecret(suiteSecret);
119+
}
120+
121+
private void configHttp(WxCpTpDefaultConfigImpl config, WxCpTpMultiProperties.ConfigStorage storage) {
122+
String httpProxyHost = storage.getHttpProxyHost();
123+
Integer httpProxyPort = storage.getHttpProxyPort();
124+
String httpProxyUsername = storage.getHttpProxyUsername();
125+
String httpProxyPassword = storage.getHttpProxyPassword();
126+
if (StringUtils.isNotBlank(httpProxyHost)) {
127+
config.setHttpProxyHost(httpProxyHost);
128+
if (httpProxyPort != null) {
129+
config.setHttpProxyPort(httpProxyPort);
130+
}
131+
if (StringUtils.isNotBlank(httpProxyUsername)) {
132+
config.setHttpProxyUsername(httpProxyUsername);
133+
}
134+
if (StringUtils.isNotBlank(httpProxyPassword)) {
135+
config.setHttpProxyPassword(httpProxyPassword);
136+
}
137+
}
138+
}
139+
}

0 commit comments

Comments
 (0)