瀏覽代碼

:new: #3360 【小程序】增加支持多小程序账号的spring-boot-starter组件

monch 8 月之前
父節點
當前提交
43ad965cee
共有 21 個文件被更改,包括 886 次插入33 次删除
  1. 1 0
      spring-boot-starters/pom.xml
  2. 96 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/README.md
  3. 72 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/pom.xml
  4. 14 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/autoconfigure/WxMaMultiAutoConfiguration.java
  5. 25 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/configuration/WxMaMultiServiceConfiguration.java
  6. 147 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/configuration/services/AbstractWxMaConfiguration.java
  7. 76 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/configuration/services/WxMaInJedisConfiguration.java
  8. 39 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/configuration/services/WxMaInMemoryConfiguration.java
  9. 67 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/configuration/services/WxMaInRedissonConfiguration.java
  10. 154 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaMultiProperties.java
  11. 56 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaMultiRedisProperties.java
  12. 40 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaSingleProperties.java
  13. 27 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/service/WxMaMultiServices.java
  14. 36 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/service/WxMaMultiServicesImpl.java
  15. 2 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/resources/META-INF/spring.factories
  16. 1 0
      spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  17. 1 1
      spring-boot-starters/wx-java-mp-multi-spring-boot-starter/README.md
  18. 7 7
      spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/configuration/services/AbstractWxMpConfiguration.java
  19. 11 11
      spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/configuration/services/WxMpInJedisConfiguration.java
  20. 4 4
      spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/configuration/services/WxMpInMemoryConfiguration.java
  21. 10 10
      spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/configuration/services/WxMpInRedissonConfiguration.java

+ 1 - 0
spring-boot-starters/pom.xml

@@ -18,6 +18,7 @@
   </properties>
 
   <modules>
+    <module>wx-java-miniapp-multi-spring-boot-starter</module>
     <module>wx-java-miniapp-spring-boot-starter</module>
     <module>wx-java-mp-multi-spring-boot-starter</module>
     <module>wx-java-mp-spring-boot-starter</module>

+ 96 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/README.md

@@ -0,0 +1,96 @@
+# wx-java-miniapp-multi-spring-boot-starter
+
+## 快速开始
+
+1. 引入依赖
+    ```xml
+    <dependency>
+        <groupId>com.github.binarywang</groupId>
+        <artifactId>wx-java-miniapp-multi-spring-boot-starter</artifactId>
+        <version>${version}</version>
+    </dependency>
+    ```
+2. 添加配置(application.properties)
+    ```properties
+    # 公众号配置
+    ## 应用 1 配置(必填)
+    wx.ma.apps.tenantId1.app-id=appId
+    wx.ma.apps.tenantId1.app-secret=@secret
+    ## 选填
+    wx.ma.apps.tenantId1.token=@token
+    wx.ma.apps.tenantId1.aes-key=@aesKey
+    wx.ma.apps.tenantId1.use-stable-access-token=@useStableAccessToken
+    ## 应用 2 配置(必填)
+    wx.ma.apps.tenantId2.app-id=@appId
+    wx.ma.apps.tenantId2.app-secret =@secret
+    ## 选填
+    wx.ma.apps.tenantId2.token=@token
+    wx.ma.apps.tenantId2.aes-key=@aesKey
+    wx.ma.apps.tenantId2.use-stable-access-token=@useStableAccessToken
+   
+    # ConfigStorage 配置(选填)
+    ## 配置类型: memory(默认), jedis, redisson
+    wx.ma.config-storage.type=memory
+    ## 相关redis前缀配置: wx:ma:multi(默认)
+    wx.ma.config-storage.key-prefix=wx:ma:multi
+    wx.ma.config-storage.redis.host=127.0.0.1
+    wx.ma.config-storage.redis.port=6379
+	  ## 单机和 sentinel 同时存在时,优先使用sentinel配置
+	  # wx.ma.config-storage.redis.sentinel-ips=127.0.0.1:16379,127.0.0.1:26379
+	  # wx.ma.config-storage.redis.sentinel-name=mymaster 
+   
+    # http 客户端配置(选填)
+    ## # http客户端类型: http_client(默认), ok_http, jodd_http
+    wx.ma.config-storage.http-client-type=http_client
+    wx.ma.config-storage.http-proxy-host=
+    wx.ma.config-storage.http-proxy-port=
+    wx.ma.config-storage.http-proxy-username=
+    wx.ma.config-storage.http-proxy-password=
+    ## 最大重试次数,默认:5 次,如果小于 0,则为 0
+    wx.ma.config-storage.max-retry-times=5
+    ## 重试时间间隔步进,默认:1000 毫秒,如果小于 0,则为 1000
+    wx.ma.config-storage.retry-sleep-millis=1000
+    ```
+3. 自动注入的类型:`WxMaMultiServices`
+
+4. 使用样例
+
+```java
+import com.binarywang.spring.starter.wxjava.miniapp.service.WxMaMultiServices;
+import com.binarywang.spring.starter.wxjava.miniapp.service.WxMaMultiServices;
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.api.WxMaUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class DemoService {
+  @Autowired
+  private WxMaMultiServices wxMaMultiServices;
+
+  public void test() {
+    // 应用 1 的 WxMaService
+    WxMaService wxMaService1 = wxMaMultiServices.getWxMaService("tenantId1");
+    WxMaUserService userService1 = wxMaService1.getUserService();
+    userService1.userInfo("xxx");
+    // todo ...
+
+    // 应用 2 的 WxMaService
+    WxMaService wxMaService2 = wxMaMultiServices.getWxMaService("tenantId2");
+    WxMaUserService userService2 = wxMaService2.getUserService();
+    userService2.userInfo("xxx");
+    // todo ...
+
+    // 应用 3 的 WxMaService
+    WxMaService wxMaService3 = wxMaMultiServices.getWxMaService("tenantId3");
+    // 判断是否为空
+    if (wxMaService3 == null) {
+      // todo wxMaService3 为空,请先配置 tenantId3 微信公众号应用参数
+      return;
+    }
+    WxMaUserService userService3 = wxMaService3.getUserService();
+    userService3.userInfo("xxx");
+    // todo ...
+  }
+}
+```

+ 72 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/pom.xml

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>wx-java-spring-boot-starters</artifactId>
+    <groupId>com.github.binarywang</groupId>
+    <version>4.6.4.B</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>wx-java-miniapp-multi-spring-boot-starter</artifactId>
+  <name>WxJava - Spring Boot Starter for MiniApp::支持多账号配置</name>
+  <description>微信公众号开发的 Spring Boot Starter::支持多账号配置</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>com.github.binarywang</groupId>
+      <artifactId>weixin-java-miniapp</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>redis.clients</groupId>
+      <artifactId>jedis</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.redisson</groupId>
+      <artifactId>redisson</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.data</groupId>
+      <artifactId>spring-data-redis</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jodd</groupId>
+      <artifactId>jodd-http</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.squareup.okhttp3</groupId>
+      <artifactId>okhttp</artifactId>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-maven-plugin</artifactId>
+        <version>${spring.boot.version}</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <version>2.2.1</version>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <goals>
+              <goal>jar-no-fork</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>

+ 14 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/autoconfigure/WxMaMultiAutoConfiguration.java

@@ -0,0 +1,14 @@
+package com.binarywang.spring.starter.wxjava.miniapp.autoconfigure;
+
+import com.binarywang.spring.starter.wxjava.miniapp.configuration.WxMaMultiServiceConfiguration;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+/**
+ * @author monch
+ * created on 2024/9/6
+ */
+@Configuration
+@Import(WxMaMultiServiceConfiguration.class)
+public class WxMaMultiAutoConfiguration {
+}

+ 25 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/configuration/WxMaMultiServiceConfiguration.java

@@ -0,0 +1,25 @@
+package com.binarywang.spring.starter.wxjava.miniapp.configuration;
+
+import com.binarywang.spring.starter.wxjava.miniapp.configuration.services.WxMaInJedisConfiguration;
+import com.binarywang.spring.starter.wxjava.miniapp.configuration.services.WxMaInMemoryConfiguration;
+import com.binarywang.spring.starter.wxjava.miniapp.configuration.services.WxMaInRedissonConfiguration;
+import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaMultiProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+/**
+ * 微信小程序相关服务自动注册
+ *
+ * @author monch
+ * created on 2024/9/6
+ */
+@Configuration
+@EnableConfigurationProperties(WxMaMultiProperties.class)
+@Import({
+  WxMaInJedisConfiguration.class,
+  WxMaInMemoryConfiguration.class,
+  WxMaInRedissonConfiguration.class,
+})
+public class WxMaMultiServiceConfiguration {
+}

+ 147 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/configuration/services/AbstractWxMaConfiguration.java

@@ -0,0 +1,147 @@
+package com.binarywang.spring.starter.wxjava.miniapp.configuration.services;
+
+import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaMultiProperties;
+import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaSingleProperties;
+import com.binarywang.spring.starter.wxjava.miniapp.service.WxMaMultiServices;
+import com.binarywang.spring.starter.wxjava.miniapp.service.WxMaMultiServicesImpl;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.api.impl.WxMaServiceHttpClientImpl;
+import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
+import cn.binarywang.wx.miniapp.api.impl.WxMaServiceJoddHttpImpl;
+import cn.binarywang.wx.miniapp.api.impl.WxMaServiceOkHttpImpl;
+import cn.binarywang.wx.miniapp.config.WxMaConfig;
+import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * WxMaConfigStorage 抽象配置类
+ *
+ * @author monch
+ * created on 2024/9/6
+ */
+@RequiredArgsConstructor
+@Slf4j
+public abstract class AbstractWxMaConfiguration {
+
+  protected WxMaMultiServices wxMaMultiServices(WxMaMultiProperties wxMaMultiProperties) {
+    Map<String, WxMaSingleProperties> appsMap = wxMaMultiProperties.getApps();
+    if (appsMap == null || appsMap.isEmpty()) {
+      log.warn("微信公众号应用参数未配置,通过 WxMaMultiServices#getWxMaService(\"tenantId\")获取实例将返回空");
+      return new WxMaMultiServicesImpl();
+    }
+    /**
+     * 校验 appId 是否唯一,避免使用 redis 缓存 token、ticket 时错乱。
+     *
+     * 查看 {@link cn.binarywang.wx.miniapp.config.impl.WxMaRedisConfigImpl#setAppId(String)}
+     */
+    Collection<WxMaSingleProperties> apps = appsMap.values();
+    if (apps.size() > 1) {
+      // 校验 appId 是否唯一
+      boolean multi = apps.stream()
+        // 没有 appId,如果不判断是否为空,这里会报 NPE 异常
+        .collect(Collectors.groupingBy(c -> c.getAppId() == null ? 0 : c.getAppId(), Collectors.counting()))
+        .entrySet().stream().anyMatch(e -> e.getValue() > 1);
+      if (multi) {
+        throw new RuntimeException("请确保微信公众号配置 appId 的唯一性");
+      }
+    }
+    WxMaMultiServicesImpl services = new WxMaMultiServicesImpl();
+
+    Set<Map.Entry<String, WxMaSingleProperties>> entries = appsMap.entrySet();
+    for (Map.Entry<String, WxMaSingleProperties> entry : entries) {
+      String tenantId = entry.getKey();
+      WxMaSingleProperties wxMaSingleProperties = entry.getValue();
+      WxMaDefaultConfigImpl storage = this.wxMaConfigStorage(wxMaMultiProperties);
+      this.configApp(storage, wxMaSingleProperties);
+      this.configHttp(storage, wxMaMultiProperties.getConfigStorage());
+      WxMaService wxMaService = this.wxMaService(storage, wxMaMultiProperties);
+      services.addWxMaService(tenantId, wxMaService);
+    }
+    return services;
+  }
+
+  /**
+   * 配置 WxMaDefaultConfigImpl
+   *
+   * @param wxMaMultiProperties 参数
+   * @return WxMaDefaultConfigImpl
+   */
+  protected abstract WxMaDefaultConfigImpl wxMaConfigStorage(WxMaMultiProperties wxMaMultiProperties);
+
+  public WxMaService wxMaService(WxMaConfig wxMaConfig, WxMaMultiProperties wxMaMultiProperties) {
+    WxMaMultiProperties.ConfigStorage storage = wxMaMultiProperties.getConfigStorage();
+    WxMaMultiProperties.HttpClientType httpClientType = storage.getHttpClientType();
+    WxMaService wxMaService;
+    switch (httpClientType) {
+      case OK_HTTP:
+        wxMaService = new WxMaServiceOkHttpImpl();
+        break;
+      case JODD_HTTP:
+        wxMaService = new WxMaServiceJoddHttpImpl();
+        break;
+      case HTTP_CLIENT:
+        wxMaService = new WxMaServiceHttpClientImpl();
+        break;
+      default:
+        wxMaService = new WxMaServiceImpl();
+        break;
+    }
+
+    wxMaService.setWxMaConfig(wxMaConfig);
+    int maxRetryTimes = storage.getMaxRetryTimes();
+    if (maxRetryTimes < 0) {
+      maxRetryTimes = 0;
+    }
+    int retrySleepMillis = storage.getRetrySleepMillis();
+    if (retrySleepMillis < 0) {
+      retrySleepMillis = 1000;
+    }
+    wxMaService.setRetrySleepMillis(retrySleepMillis);
+    wxMaService.setMaxRetryTimes(maxRetryTimes);
+    return wxMaService;
+  }
+
+  private void configApp(WxMaDefaultConfigImpl config, WxMaSingleProperties corpProperties) {
+    String appId = corpProperties.getAppId();
+    String appSecret = corpProperties.getAppSecret();
+    String token = corpProperties.getToken();
+    String aesKey = corpProperties.getAesKey();
+    boolean useStableAccessToken = corpProperties.isUseStableAccessToken();
+
+    config.setAppid(appId);
+    config.setSecret(appSecret);
+    if (StringUtils.isNotBlank(token)) {
+      config.setToken(token);
+    }
+    if (StringUtils.isNotBlank(aesKey)) {
+      config.setAesKey(aesKey);
+    }
+    config.useStableAccessToken(useStableAccessToken);
+  }
+
+  private void configHttp(WxMaDefaultConfigImpl config, WxMaMultiProperties.ConfigStorage storage) {
+    String httpProxyHost = storage.getHttpProxyHost();
+    Integer httpProxyPort = storage.getHttpProxyPort();
+    String httpProxyUsername = storage.getHttpProxyUsername();
+    String httpProxyPassword = storage.getHttpProxyPassword();
+    if (StringUtils.isNotBlank(httpProxyHost)) {
+      config.setHttpProxyHost(httpProxyHost);
+      if (httpProxyPort != null) {
+        config.setHttpProxyPort(httpProxyPort);
+      }
+      if (StringUtils.isNotBlank(httpProxyUsername)) {
+        config.setHttpProxyUsername(httpProxyUsername);
+      }
+      if (StringUtils.isNotBlank(httpProxyPassword)) {
+        config.setHttpProxyPassword(httpProxyPassword);
+      }
+    }
+  }
+}

+ 76 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/configuration/services/WxMaInJedisConfiguration.java

@@ -0,0 +1,76 @@
+package com.binarywang.spring.starter.wxjava.miniapp.configuration.services;
+
+import cn.binarywang.wx.miniapp.config.impl.WxMaRedisConfigImpl;
+import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaMultiProperties;
+import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaMultiRedisProperties;
+import com.binarywang.spring.starter.wxjava.miniapp.service.WxMaMultiServices;
+import lombok.RequiredArgsConstructor;
+import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import redis.clients.jedis.JedisPool;
+import redis.clients.jedis.JedisPoolConfig;
+
+/**
+ * 自动装配基于 jedis 策略配置
+ *
+ * @author monch
+ * created on 2024/9/6
+ */
+@Configuration
+@ConditionalOnProperty(
+  prefix = WxMaMultiProperties.PREFIX + ".config-storage", name = "type", havingValue = "jedis"
+)
+@RequiredArgsConstructor
+public class WxMaInJedisConfiguration extends AbstractWxMaConfiguration {
+  private final WxMaMultiProperties wxMaMultiProperties;
+  private final ApplicationContext applicationContext;
+
+  @Bean
+  public WxMaMultiServices wxMaMultiServices() {
+    return this.wxMaMultiServices(wxMaMultiProperties);
+  }
+
+  @Override
+  protected WxMaDefaultConfigImpl wxMaConfigStorage(WxMaMultiProperties wxMaMultiProperties) {
+    return this.configRedis(wxMaMultiProperties);
+  }
+
+  private WxMaDefaultConfigImpl configRedis(WxMaMultiProperties wxMaMultiProperties) {
+    WxMaMultiRedisProperties wxMaMultiRedisProperties = wxMaMultiProperties.getConfigStorage().getRedis();
+    JedisPool jedisPool;
+    if (wxMaMultiRedisProperties != null && StringUtils.isNotEmpty(wxMaMultiRedisProperties.getHost())) {
+      jedisPool = getJedisPool(wxMaMultiProperties);
+    } else {
+      jedisPool = applicationContext.getBean(JedisPool.class);
+    }
+    return new WxMaRedisConfigImpl(jedisPool);
+  }
+
+  private JedisPool getJedisPool(WxMaMultiProperties wxMaMultiProperties) {
+    WxMaMultiProperties.ConfigStorage storage = wxMaMultiProperties.getConfigStorage();
+    WxMaMultiRedisProperties redis = storage.getRedis();
+
+    JedisPoolConfig config = new JedisPoolConfig();
+    if (redis.getMaxActive() != null) {
+      config.setMaxTotal(redis.getMaxActive());
+    }
+    if (redis.getMaxIdle() != null) {
+      config.setMaxIdle(redis.getMaxIdle());
+    }
+    if (redis.getMaxWaitMillis() != null) {
+      config.setMaxWaitMillis(redis.getMaxWaitMillis());
+    }
+    if (redis.getMinIdle() != null) {
+      config.setMinIdle(redis.getMinIdle());
+    }
+    config.setTestOnBorrow(true);
+    config.setTestWhileIdle(true);
+
+    return new JedisPool(config, redis.getHost(), redis.getPort(),
+      redis.getTimeout(), redis.getPassword(), redis.getDatabase());
+  }
+}

+ 39 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/configuration/services/WxMaInMemoryConfiguration.java

@@ -0,0 +1,39 @@
+package com.binarywang.spring.starter.wxjava.miniapp.configuration.services;
+
+import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
+import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaMultiProperties;
+import com.binarywang.spring.starter.wxjava.miniapp.service.WxMaMultiServices;
+import lombok.RequiredArgsConstructor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 自动装配基于内存策略配置
+ *
+ * @author monch
+ * created on 2024/9/6
+ */
+@Configuration
+@ConditionalOnProperty(
+  prefix = WxMaMultiProperties.PREFIX + ".config-storage", name = "type", havingValue = "memory", matchIfMissing = true
+)
+@RequiredArgsConstructor
+public class WxMaInMemoryConfiguration extends AbstractWxMaConfiguration {
+  private final WxMaMultiProperties wxMaMultiProperties;
+
+  @Bean
+  public WxMaMultiServices wxMaMultiServices() {
+    return this.wxMaMultiServices(wxMaMultiProperties);
+  }
+
+  @Override
+  protected WxMaDefaultConfigImpl wxMaConfigStorage(WxMaMultiProperties wxMaMultiProperties) {
+    return this.configInMemory();
+  }
+
+  private WxMaDefaultConfigImpl configInMemory() {
+    return new WxMaDefaultConfigImpl();
+    // return new WxMaDefaultConfigImpl();
+  }
+}

+ 67 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/configuration/services/WxMaInRedissonConfiguration.java

@@ -0,0 +1,67 @@
+package com.binarywang.spring.starter.wxjava.miniapp.configuration.services;
+
+import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
+import cn.binarywang.wx.miniapp.config.impl.WxMaRedissonConfigImpl;
+import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaMultiProperties;
+import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaMultiRedisProperties;
+import com.binarywang.spring.starter.wxjava.miniapp.service.WxMaMultiServices;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.redisson.config.TransportMode;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 自动装配基于 redisson 策略配置
+ *
+ * @author monch
+ * created on 2024/9/6
+ */
+@Configuration
+@ConditionalOnProperty(
+  prefix = WxMaMultiProperties.PREFIX + ".config-storage", name = "type", havingValue = "redisson"
+)
+@RequiredArgsConstructor
+public class WxMaInRedissonConfiguration extends AbstractWxMaConfiguration {
+  private final WxMaMultiProperties wxMaMultiProperties;
+  private final ApplicationContext applicationContext;
+
+  @Bean
+  public WxMaMultiServices wxMaMultiServices() {
+    return this.wxMaMultiServices(wxMaMultiProperties);
+  }
+
+  @Override
+  protected WxMaDefaultConfigImpl wxMaConfigStorage(WxMaMultiProperties wxMaMultiProperties) {
+    return this.configRedisson(wxMaMultiProperties);
+  }
+
+  private WxMaDefaultConfigImpl configRedisson(WxMaMultiProperties wxMaMultiProperties) {
+    WxMaMultiRedisProperties redisProperties = wxMaMultiProperties.getConfigStorage().getRedis();
+    RedissonClient redissonClient;
+    if (redisProperties != null && StringUtils.isNotEmpty(redisProperties.getHost())) {
+      redissonClient = getRedissonClient(wxMaMultiProperties);
+    } else {
+      redissonClient = applicationContext.getBean(RedissonClient.class);
+    }
+    return new WxMaRedissonConfigImpl(redissonClient, wxMaMultiProperties.getConfigStorage().getKeyPrefix());
+  }
+
+  private RedissonClient getRedissonClient(WxMaMultiProperties wxMaMultiProperties) {
+    WxMaMultiProperties.ConfigStorage storage = wxMaMultiProperties.getConfigStorage();
+    WxMaMultiRedisProperties redis = storage.getRedis();
+
+    Config config = new Config();
+    config.useSingleServer()
+      .setAddress("redis://" + redis.getHost() + ":" + redis.getPort())
+      .setDatabase(redis.getDatabase())
+      .setPassword(redis.getPassword());
+    config.setTransportMode(TransportMode.NIO);
+    return Redisson.create(config);
+  }
+}

+ 154 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaMultiProperties.java

@@ -0,0 +1,154 @@
+package com.binarywang.spring.starter.wxjava.miniapp.properties;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.context.properties.NestedConfigurationProperty;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author monch
+ * created on 2024/9/6
+ */
+@Data
+@NoArgsConstructor
+@ConfigurationProperties(WxMaMultiProperties.PREFIX)
+public class WxMaMultiProperties implements Serializable {
+  private static final long serialVersionUID = -5358245184407791011L;
+  public static final String PREFIX = "wx.ma";
+
+  private Map<String, WxMaSingleProperties> apps = new HashMap<>();
+
+  /**
+   * 自定义host配置
+   */
+  private HostConfig hosts;
+
+  /**
+   * 存储策略
+   */
+  private final ConfigStorage configStorage = new ConfigStorage();
+
+  @Data
+  @NoArgsConstructor
+  public static class HostConfig implements Serializable {
+    private static final long serialVersionUID = -4172767630740346001L;
+
+    /**
+     * 对应于:https://api.weixin.qq.com
+     */
+    private String apiHost;
+
+    /**
+     * 对应于:https://open.weixin.qq.com
+     */
+    private String openHost;
+
+    /**
+     * 对应于:https://mp.weixin.qq.com
+     */
+    private String mpHost;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class ConfigStorage implements Serializable {
+    private static final long serialVersionUID = 4815731027000065434L;
+
+    /**
+     * 存储类型.
+     */
+    private StorageType type = StorageType.MEMORY;
+
+    /**
+     * 指定key前缀.
+     */
+    private String keyPrefix = "wx:ma:multi";
+
+    /**
+     * redis连接配置.
+     */
+    @NestedConfigurationProperty
+    private final WxMaMultiRedisProperties redis = new WxMaMultiRedisProperties();
+
+    /**
+     * http客户端类型.
+     */
+    private HttpClientType httpClientType = HttpClientType.HTTP_CLIENT;
+
+    /**
+     * http代理主机.
+     */
+    private String httpProxyHost;
+
+    /**
+     * http代理端口.
+     */
+    private Integer httpProxyPort;
+
+    /**
+     * http代理用户名.
+     */
+    private String httpProxyUsername;
+
+    /**
+     * http代理密码.
+     */
+    private String httpProxyPassword;
+
+    /**
+     * http 请求最大重试次数
+     * <pre>
+     *   {@link cn.binarywang.wx.miniapp.api.WxMaService#setMaxRetryTimes(int)}
+     *   {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setMaxRetryTimes(int)}
+     * </pre>
+     */
+    private int maxRetryTimes = 5;
+
+    /**
+     * http 请求重试间隔
+     * <pre>
+     *   {@link cn.binarywang.wx.miniapp.api.WxMaService#setRetrySleepMillis(int)}
+     *   {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setRetrySleepMillis(int)}
+     * </pre>
+     */
+    private int retrySleepMillis = 1000;
+  }
+
+  public enum StorageType {
+    /**
+     * 内存
+     */
+    MEMORY,
+    /**
+     * jedis
+     */
+    JEDIS,
+    /**
+     * redisson
+     */
+    REDISSON,
+    /**
+     * redisTemplate
+     */
+    REDIS_TEMPLATE
+  }
+
+  public enum HttpClientType {
+    /**
+     * HttpClient
+     */
+    HTTP_CLIENT,
+    /**
+     * OkHttp
+     */
+    OK_HTTP,
+    /**
+     * JoddHttp
+     */
+    JODD_HTTP
+  }
+}

+ 56 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaMultiRedisProperties.java

@@ -0,0 +1,56 @@
+package com.binarywang.spring.starter.wxjava.miniapp.properties;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @author monch
+ * created on 2024/9/6
+ */
+@Data
+@NoArgsConstructor
+public class WxMaMultiRedisProperties implements Serializable {
+  private static final long serialVersionUID = -5924815351660074401L;
+
+  /**
+   * 主机地址.
+   */
+  private String host = "127.0.0.1";
+
+  /**
+   * 端口号.
+   */
+  private int port = 6379;
+
+  /**
+   * 密码.
+   */
+  private String password;
+
+  /**
+   * 超时.
+   */
+  private int timeout = 2000;
+
+  /**
+   * 数据库.
+   */
+  private int database = 0;
+
+  /**
+   * sentinel ips
+   */
+  private String sentinelIps;
+
+  /**
+   * sentinel name
+   */
+  private String sentinelName;
+
+  private Integer maxActive;
+  private Integer maxIdle;
+  private Integer maxWaitMillis;
+  private Integer minIdle;
+}

+ 40 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaSingleProperties.java

@@ -0,0 +1,40 @@
+package com.binarywang.spring.starter.wxjava.miniapp.properties;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @author monch
+ * created on 2024/9/6
+ */
+@Data
+@NoArgsConstructor
+public class WxMaSingleProperties implements Serializable {
+  private static final long serialVersionUID = 1980986361098922525L;
+  /**
+   * 设置微信公众号的 appid.
+   */
+  private String appId;
+
+  /**
+   * 设置微信公众号的 app secret.
+   */
+  private String appSecret;
+
+  /**
+   * 设置微信公众号的 token.
+   */
+  private String token;
+
+  /**
+   * 设置微信公众号的 EncodingAESKey.
+   */
+  private String aesKey;
+
+  /**
+   * 是否使用稳定版 Access Token
+   */
+  private boolean useStableAccessToken = false;
+}

+ 27 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/service/WxMaMultiServices.java

@@ -0,0 +1,27 @@
+package com.binarywang.spring.starter.wxjava.miniapp.service;
+
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+
+/**
+ * 微信小程序 {@link WxMaService} 所有实例存放类.
+ *
+ * @author monch
+ * created on 2024/9/6
+ */
+public interface WxMaMultiServices {
+  /**
+   * 通过租户 Id 获取 WxMaService
+   *
+   * @param tenantId 租户 Id
+   * @return WxMaService
+   */
+  WxMaService getWxMaService(String tenantId);
+
+  /**
+   * 根据租户 Id,从列表中移除一个 WxMaService 实例
+   *
+   * @param tenantId 租户 Id
+   */
+  void removeWxMaService(String tenantId);
+}

+ 36 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/service/WxMaMultiServicesImpl.java

@@ -0,0 +1,36 @@
+package com.binarywang.spring.starter.wxjava.miniapp.service;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 微信小程序 {@link com.binarywang.spring.starter.wxjava.miniapp.service.WxMaMultiServices} 默认实现
+ *
+ * @author monch
+ * created on 2024/9/6
+ */
+public class WxMaMultiServicesImpl implements com.binarywang.spring.starter.wxjava.miniapp.service.WxMaMultiServices {
+  private final Map<String, WxMaService> services = new ConcurrentHashMap<>();
+
+  @Override
+  public WxMaService getWxMaService(String tenantId) {
+    return this.services.get(tenantId);
+  }
+
+  /**
+   * 根据租户 Id,添加一个 WxMaService 到列表
+   *
+   * @param tenantId    租户 Id
+   * @param wxMaService WxMaService 实例
+   */
+  public void addWxMaService(String tenantId, WxMaService wxMaService) {
+    this.services.put(tenantId, wxMaService);
+  }
+
+  @Override
+  public void removeWxMaService(String tenantId) {
+    this.services.remove(tenantId);
+  }
+}

+ 2 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/resources/META-INF/spring.factories

@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.binarywang.spring.starter.wxjava.miniapp.autoconfigure.WxMaMultiAutoConfiguration

+ 1 - 0
spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -0,0 +1 @@
+com.binarywang.spring.starter.wxjava.miniapp.autoconfigure.WxMaMultiAutoConfiguration

+ 1 - 1
spring-boot-starters/wx-java-mp-multi-spring-boot-starter/README.md

@@ -61,7 +61,7 @@
 4. 使用样例
 
 ```java
-import com.binarywang.spring.starter.wxjava.mp.service.WxMpMultiServices;
+import com.binarywang.spring.starter.wxjava.mp.service.WxMaMultiServices;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.WxMpUserService;
 import org.springframework.beans.factory.annotation.Autowired;

+ 7 - 7
spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/configuration/services/AbstractWxMpConfiguration.java

@@ -31,8 +31,8 @@ import java.util.stream.Collectors;
 @Slf4j
 public abstract class AbstractWxMpConfiguration {
 
-  protected WxMpMultiServices wxMpMultiServices(WxMpMultiProperties wxCpMultiProperties) {
-    Map<String, WxMpSingleProperties> appsMap = wxCpMultiProperties.getApps();
+  protected WxMpMultiServices wxMpMultiServices(WxMpMultiProperties wxMpMultiProperties) {
+    Map<String, WxMpSingleProperties> appsMap = wxMpMultiProperties.getApps();
     if (appsMap == null || appsMap.isEmpty()) {
       log.warn("微信公众号应用参数未配置,通过 WxMpMultiServices#getWxMpService(\"tenantId\")获取实例将返回空");
       return new WxMpMultiServicesImpl();
@@ -59,12 +59,12 @@ public abstract class AbstractWxMpConfiguration {
     for (Map.Entry<String, WxMpSingleProperties> entry : entries) {
       String tenantId = entry.getKey();
       WxMpSingleProperties wxMpSingleProperties = entry.getValue();
-      WxMpDefaultConfigImpl storage = this.wxMpConfigStorage(wxCpMultiProperties);
+      WxMpDefaultConfigImpl storage = this.wxMpConfigStorage(wxMpMultiProperties);
       this.configApp(storage, wxMpSingleProperties);
-      this.configHttp(storage, wxCpMultiProperties.getConfigStorage());
-      this.configHost(storage, wxCpMultiProperties.getHosts());
-      WxMpService wxCpService = this.wxMpService(storage, wxCpMultiProperties);
-      services.addWxMpService(tenantId, wxCpService);
+      this.configHttp(storage, wxMpMultiProperties.getConfigStorage());
+      this.configHost(storage, wxMpMultiProperties.getHosts());
+      WxMpService wxMpService = this.wxMpService(storage, wxMpMultiProperties);
+      services.addWxMpService(tenantId, wxMpService);
     }
     return services;
   }

+ 11 - 11
spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/configuration/services/WxMpInJedisConfiguration.java

@@ -27,32 +27,32 @@ import redis.clients.jedis.JedisPoolConfig;
 )
 @RequiredArgsConstructor
 public class WxMpInJedisConfiguration extends AbstractWxMpConfiguration {
-  private final WxMpMultiProperties wxCpMultiProperties;
+  private final WxMpMultiProperties wxMpMultiProperties;
   private final ApplicationContext applicationContext;
 
   @Bean
   public WxMpMultiServices wxMpMultiServices() {
-    return this.wxMpMultiServices(wxCpMultiProperties);
+    return this.wxMpMultiServices(wxMpMultiProperties);
   }
 
   @Override
-  protected WxMpDefaultConfigImpl wxMpConfigStorage(WxMpMultiProperties wxCpMultiProperties) {
-    return this.configRedis(wxCpMultiProperties);
+  protected WxMpDefaultConfigImpl wxMpConfigStorage(WxMpMultiProperties wxMpMultiProperties) {
+    return this.configRedis(wxMpMultiProperties);
   }
 
-  private WxMpDefaultConfigImpl configRedis(WxMpMultiProperties wxCpMultiProperties) {
-    WxMpMultiRedisProperties wxCpMultiRedisProperties = wxCpMultiProperties.getConfigStorage().getRedis();
+  private WxMpDefaultConfigImpl configRedis(WxMpMultiProperties wxMpMultiProperties) {
+    WxMpMultiRedisProperties wxMpMultiRedisProperties = wxMpMultiProperties.getConfigStorage().getRedis();
     JedisPool jedisPool;
-    if (wxCpMultiRedisProperties != null && StringUtils.isNotEmpty(wxCpMultiRedisProperties.getHost())) {
-      jedisPool = getJedisPool(wxCpMultiProperties);
+    if (wxMpMultiRedisProperties != null && StringUtils.isNotEmpty(wxMpMultiRedisProperties.getHost())) {
+      jedisPool = getJedisPool(wxMpMultiProperties);
     } else {
       jedisPool = applicationContext.getBean(JedisPool.class);
     }
-    return new WxMpRedisConfigImpl(new JedisWxRedisOps(jedisPool), wxCpMultiProperties.getConfigStorage().getKeyPrefix());
+    return new WxMpRedisConfigImpl(new JedisWxRedisOps(jedisPool), wxMpMultiProperties.getConfigStorage().getKeyPrefix());
   }
 
-  private JedisPool getJedisPool(WxMpMultiProperties wxCpMultiProperties) {
-    WxMpMultiProperties.ConfigStorage storage = wxCpMultiProperties.getConfigStorage();
+  private JedisPool getJedisPool(WxMpMultiProperties wxMpMultiProperties) {
+    WxMpMultiProperties.ConfigStorage storage = wxMpMultiProperties.getConfigStorage();
     WxMpMultiRedisProperties redis = storage.getRedis();
 
     JedisPoolConfig config = new JedisPoolConfig();

+ 4 - 4
spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/configuration/services/WxMpInMemoryConfiguration.java

@@ -21,15 +21,15 @@ import org.springframework.context.annotation.Configuration;
 )
 @RequiredArgsConstructor
 public class WxMpInMemoryConfiguration extends AbstractWxMpConfiguration {
-  private final WxMpMultiProperties wxCpMultiProperties;
+  private final WxMpMultiProperties wxMpMultiProperties;
 
   @Bean
-  public WxMpMultiServices wxCpMultiServices() {
-    return this.wxMpMultiServices(wxCpMultiProperties);
+  public WxMpMultiServices wxMpMultiServices() {
+    return this.wxMpMultiServices(wxMpMultiProperties);
   }
 
   @Override
-  protected WxMpDefaultConfigImpl wxMpConfigStorage(WxMpMultiProperties wxCpMultiProperties) {
+  protected WxMpDefaultConfigImpl wxMpConfigStorage(WxMpMultiProperties wxMpMultiProperties) {
     return this.configInMemory();
   }
 

+ 10 - 10
spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/configuration/services/WxMpInRedissonConfiguration.java

@@ -28,32 +28,32 @@ import org.springframework.context.annotation.Configuration;
 )
 @RequiredArgsConstructor
 public class WxMpInRedissonConfiguration extends AbstractWxMpConfiguration {
-  private final WxMpMultiProperties wxCpMultiProperties;
+  private final WxMpMultiProperties wxMpMultiProperties;
   private final ApplicationContext applicationContext;
 
   @Bean
   public WxMpMultiServices wxMpMultiServices() {
-    return this.wxMpMultiServices(wxCpMultiProperties);
+    return this.wxMpMultiServices(wxMpMultiProperties);
   }
 
   @Override
-  protected WxMpDefaultConfigImpl wxMpConfigStorage(WxMpMultiProperties wxCpMultiProperties) {
-    return this.configRedisson(wxCpMultiProperties);
+  protected WxMpDefaultConfigImpl wxMpConfigStorage(WxMpMultiProperties wxMpMultiProperties) {
+    return this.configRedisson(wxMpMultiProperties);
   }
 
-  private WxMpDefaultConfigImpl configRedisson(WxMpMultiProperties wxCpMultiProperties) {
-    WxMpMultiRedisProperties redisProperties = wxCpMultiProperties.getConfigStorage().getRedis();
+  private WxMpDefaultConfigImpl configRedisson(WxMpMultiProperties wxMpMultiProperties) {
+    WxMpMultiRedisProperties redisProperties = wxMpMultiProperties.getConfigStorage().getRedis();
     RedissonClient redissonClient;
     if (redisProperties != null && StringUtils.isNotEmpty(redisProperties.getHost())) {
-      redissonClient = getRedissonClient(wxCpMultiProperties);
+      redissonClient = getRedissonClient(wxMpMultiProperties);
     } else {
       redissonClient = applicationContext.getBean(RedissonClient.class);
     }
-    return new WxMpRedissonConfigImpl(redissonClient, wxCpMultiProperties.getConfigStorage().getKeyPrefix());
+    return new WxMpRedissonConfigImpl(redissonClient, wxMpMultiProperties.getConfigStorage().getKeyPrefix());
   }
 
-  private RedissonClient getRedissonClient(WxMpMultiProperties wxCpMultiProperties) {
-    WxMpMultiProperties.ConfigStorage storage = wxCpMultiProperties.getConfigStorage();
+  private RedissonClient getRedissonClient(WxMpMultiProperties wxMpMultiProperties) {
+    WxMpMultiProperties.ConfigStorage storage = wxMpMultiProperties.getConfigStorage();
     WxMpMultiRedisProperties redis = storage.getRedis();
 
     Config config = new Config();