1

spring-boot-starter-weixin是jfinal-weixin的spring boot版本,以前一直在用jfinal-weixin做为开发工具包,也一直没有尝试过支持多公众号,最近正好有需求要求支持多公众号,就来研究一番它是如何支持多公众号的。

找到源码,打开后发现有个拦截器,我们看看拦截器做了什么。

微信后台如何配置来支持多公众号

在preHandle中有比较重要的几行代码,我们拿出来单独分析一下。

String appId = request.getParameter(weixinProperties.getAppIdKey());
// weixinProperties类
private String appIdKey = "appId"; 

这一行代码重要是获取参数的,也就是在我们微信后台配置开发者url的时候添加的参数,参数名是appId。

// 判断是否多公众号,将 appId 与当前线程绑定,以便在后续操作中方便获取ApiConfig对象:
Object bean = handlerMethod.getBean();
boolean isWx = bean instanceof MsgController;
String token;
if (isWx) {
    if (StringUtils.hasText(appId)) {
        ApiConfigKit.setThreadLocalAppId(appId);
        token = ApiConfigKit.getApiConfig(appId).getToken();
    } else {
        token = ApiConfigKit.getApiConfig().getToken();
    }
} else {
    token = WxaConfigKit.getWxaConfig().getToken();
}

这一段代码主要是根据微信后台传过来的appId来获取对应微信公众号的token,来跟微信后台传过来的token进行匹配。

公众号后台配置如下:

如何支持多公众号

在MsgInterceptor中有用到ApiConfigKit.getApiConfig(),我们打开这个类看一下,他具体做了什么工作。

public static ApiConfig getApiConfig(String appId) {
    log.debug("appId: " + appId);
    ApiConfig cfg = (ApiConfig)CFG_MAP.get(appId);
    if (cfg == null) {
        throw new IllegalStateException("需事先调用 ApiConfigKit.putApiConfig(apiConfig) 将               
             appId对应的 ApiConfig 对象存入,如JFinalConfig.afterJFinalStart()中调用, 才可以使用             
             ApiConfigKit.getApiConfig() 系列方法");
    } else {
        return cfg;
    }
}

根据自定义的异常信息,我们知道如果想要使用getApiConfig(String appId),则必须先调用putApiConfig(apiConfig),将公众号信息存入。

@Configuration
@AllArgsConstructor
public class WeixinAppConfig implements SmartInitializingSingleton {
    private final DreamWeixinProperties weixinProperties;
    private final SpringAccessTokenCache accessTokenCache;

    @Override
    public void afterSingletonsInstantiated() {
        boolean isdev = weixinProperties.isDevMode();
        ApiConfigKit.setDevMode(isdev);
        ApiConfigKit.setAccessTokenCache(accessTokenCache);
        List<DreamWeixinProperties.ApiConfig> list = weixinProperties.getWxConfigs();
        for (DreamWeixinProperties.ApiConfig apiConfig : list) {
            ApiConfig config = new ApiConfig();
            if (StrKit.notBlank(apiConfig.getAppId())) {
                config.setAppId(apiConfig.getAppId());
            }
            if (StrKit.notBlank(apiConfig.getAppSecret())) {
                config.setAppSecret(apiConfig.getAppSecret());
            }
            if (StrKit.notBlank(apiConfig.getToken())) {
                config.setToken(apiConfig.getToken());
            }
            if (StrKit.notBlank(apiConfig.getEncodingAesKey())) {
                config.setEncodingAesKey(apiConfig.getEncodingAesKey());
            }
            config.setEncryptMessage(apiConfig.isMessageEncrypt());
            ApiConfigKit.putApiConfig(config);
        }
        // 省略小程序配置
    }
}
  • afterSingletonsInstantiated:当所有单例 bean 都初始化完成以后, 容器会回调该接口的方法

这个类的目的就是在项目启动后将配置文件中的微信公众号配置取出来,循环放入ApiConfigKit。

DreamWeixinProperties部分配置如下:

@Getter
@Setter
@ConfigurationProperties("dream.weixin")
public class DreamWeixinProperties {

    /**
     * 拦截的路由,默认:/weixin/*
     */
    private String urlPatterns = "/weixin/*";
    /**    
     * 是否开发模式,默认:false
     */
    private boolean devMode = false;
    /**
     * 多公众号url挂参,默认:appId
     */
    private String appIdKey = "appId";
    /**
     * 多公众号配置
     */
    private List<ApiConfig> wxConfigs = new ArrayList<>();

    @Getter
    @Setter
    public static class ApiConfig {
        private String token;
        private String appId;
        private String appSecret;
        private String encodingAesKey;
        // 消息加密与否
        private boolean messageEncrypt = false;
    }
}

数据库获取多公众号配置

我们一般需要来在平台管理公众号,因此从数据库获取公众号配置要远比配置文件获取更加方便,我们只需要实现SmartInitializingSingleton接口,将公众号配置改为从数据库获取就可以了。

@Configuration
@AllArgsConstructor
public class WxConfig implements SmartInitializingSingleton {

    private final SpringAccessTokenCache accessTokenCache;

    @Autowired
    private WexinNoDao wexinNoDao;
    @Override
    public void afterSingletonsInstantiated() {
        ApiConfigKit.setDevMode(true);
        ApiConfigKit.setAccessTokenCache(accessTokenCache);
        /**
         * 数据库查询
         */
        List<WeixinNoBean> list = wexinNoDao.wxNoList();
        for (WeixinNoBean apiConfig : list) {
            ApiConfig config = new ApiConfig();
            if (StrKit.notBlank(apiConfig.getAppid())) {
                config.setAppId(apiConfig.getAppid());
            }
            if (StrKit.notBlank(apiConfig.getAppKey())) {
                config.setAppSecret(apiConfig.getAppKey());
            }
            if (StrKit.notBlank(apiConfig.getToken())) {
                config.setToken(apiConfig.getToken());
            }
            if (StrKit.notBlank(apiConfig.getAeskey())) {
                config.setEncodingAesKey(apiConfig.getAeskey());
            }
            config.setEncryptMessage(false);
            ApiConfigKit.putApiConfig(config);
        }
    }
}

这样,当项目启动以后,就会调用我们自定义的WxConfig来完成多公众号的配置。数据库读取公众号配置比配置文件直接读取更加灵活。因此,我也是比较推荐直接从数据库来读取公众号配置的。


Java旅途
1.1k 声望6.1k 粉丝