mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 04:08:43 +08:00 
			
		
		
		
	saas:支持社交应用的多租户配置(wx 小程序)
This commit is contained in:
		@@ -1,6 +1,8 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.api.social;
 | 
			
		||||
 | 
			
		||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.convert.social.SocialClientConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.social.SocialClientService;
 | 
			
		||||
import me.chanjar.weixin.common.bean.WxJsapiSignature;
 | 
			
		||||
@@ -32,4 +34,10 @@ public class SocialClientApiImpl implements SocialClientApi {
 | 
			
		||||
        return SocialClientConvert.INSTANCE.convert(signature);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public SocialWxPhoneNumberInfoRespDTO getWxMaPhoneNumberInfo(Integer userType, String phoneCode) {
 | 
			
		||||
        WxMaPhoneNumberInfo info = socialClientService.getWxMaPhoneNumberInfo(userType, phoneCode);
 | 
			
		||||
        return SocialClientConvert.INSTANCE.convert(info);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.convert.social;
 | 
			
		||||
 | 
			
		||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO;
 | 
			
		||||
import me.chanjar.weixin.common.bean.WxJsapiSignature;
 | 
			
		||||
import org.mapstruct.Mapper;
 | 
			
		||||
import org.mapstruct.factory.Mappers;
 | 
			
		||||
@@ -12,4 +14,6 @@ public interface SocialClientConvert {
 | 
			
		||||
 | 
			
		||||
    SocialWxJsapiSignatureRespDTO convert(WxJsapiSignature bean);
 | 
			
		||||
 | 
			
		||||
    SocialWxPhoneNumberInfoRespDTO convert(WxMaPhoneNumberInfo bean);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.service.social;
 | 
			
		||||
 | 
			
		||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
 | 
			
		||||
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
 | 
			
		||||
import com.xingyuv.jushauth.model.AuthUser;
 | 
			
		||||
import me.chanjar.weixin.common.bean.WxJsapiSignature;
 | 
			
		||||
@@ -32,8 +33,10 @@ public interface SocialClientService {
 | 
			
		||||
     */
 | 
			
		||||
    AuthUser getAuthUser(Integer socialType, Integer userType, String code, String state);
 | 
			
		||||
 | 
			
		||||
    // =================== 微信公众号独有 ===================
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建微信 JS SDK 初始化所需的签名
 | 
			
		||||
     * 创建微信公众号的 JS SDK 初始化所需的签名
 | 
			
		||||
     *
 | 
			
		||||
     * @param userType 用户类型
 | 
			
		||||
     * @param url 访问的 URL 地址
 | 
			
		||||
@@ -41,4 +44,15 @@ public interface SocialClientService {
 | 
			
		||||
     */
 | 
			
		||||
    WxJsapiSignature createWxMpJsapiSignature(Integer userType, String url);
 | 
			
		||||
 | 
			
		||||
    // =================== 微信小程序独有 ===================
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得微信小程序的手机信息
 | 
			
		||||
     *
 | 
			
		||||
     * @param userType 用户类型
 | 
			
		||||
     * @param phoneCode 手机授权码
 | 
			
		||||
     * @return 手机信息
 | 
			
		||||
     */
 | 
			
		||||
    WxMaPhoneNumberInfo getWxMaPhoneNumberInfo(Integer userType, String phoneCode);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,9 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.service.social;
 | 
			
		||||
 | 
			
		||||
import cn.binarywang.wx.miniapp.api.WxMaService;
 | 
			
		||||
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
 | 
			
		||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
 | 
			
		||||
import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl;
 | 
			
		||||
import cn.hutool.core.bean.BeanUtil;
 | 
			
		||||
import cn.hutool.core.lang.Assert;
 | 
			
		||||
import cn.hutool.core.util.ReflectUtil;
 | 
			
		||||
@@ -10,6 +14,7 @@ import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper;
 | 
			
		||||
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
 | 
			
		||||
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
 | 
			
		||||
import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
 | 
			
		||||
import com.google.common.cache.CacheLoader;
 | 
			
		||||
import com.google.common.cache.LoadingCache;
 | 
			
		||||
@@ -22,6 +27,7 @@ import com.xingyuv.jushauth.utils.AuthStateUtils;
 | 
			
		||||
import lombok.SneakyThrows;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import me.chanjar.weixin.common.bean.WxJsapiSignature;
 | 
			
		||||
import me.chanjar.weixin.common.error.WxErrorException;
 | 
			
		||||
import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
 | 
			
		||||
import me.chanjar.weixin.mp.api.WxMpService;
 | 
			
		||||
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
 | 
			
		||||
@@ -35,6 +41,7 @@ import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
 | 
			
		||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_APP_WEIXIN_MINI_APP_PHONE_CODE_ERROR;
 | 
			
		||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_AUTH_FAILURE;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -50,11 +57,11 @@ public class SocialClientServiceImpl implements SocialClientService {
 | 
			
		||||
    private YudaoAuthRequestFactory yudaoAuthRequestFactory;
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private WxMpService mpService;
 | 
			
		||||
    private WxMpService wxMpService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private WxMpProperties wxMpProperties;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private StringRedisTemplate stringRedisTemplate; // WxMpService 需要使用到,所以在 Service 注入了它
 | 
			
		||||
    @Resource
 | 
			
		||||
    private WxMpProperties mpProperties;
 | 
			
		||||
    /**
 | 
			
		||||
     * 缓存 WxMpService 对象
 | 
			
		||||
     *
 | 
			
		||||
@@ -63,14 +70,35 @@ public class SocialClientServiceImpl implements SocialClientService {
 | 
			
		||||
     *
 | 
			
		||||
     * 为什么要做 WxMpService 缓存?因为 WxMpService 构建成本比较大,所以尽量保证它是单例。
 | 
			
		||||
     */
 | 
			
		||||
    private final LoadingCache<String, WxMpService> mpServiceCache = CacheUtils.buildAsyncReloadingCache(
 | 
			
		||||
    private final LoadingCache<String, WxMpService> wxMpServiceCache = CacheUtils.buildAsyncReloadingCache(
 | 
			
		||||
            Duration.ofSeconds(10L),
 | 
			
		||||
            new CacheLoader<String, WxMpService>() {
 | 
			
		||||
 | 
			
		||||
                @Override
 | 
			
		||||
                public WxMpService load(String key) {
 | 
			
		||||
                    String[] keys = key.split(":");
 | 
			
		||||
                    return buildMpService(keys[0], keys[1]);
 | 
			
		||||
                    return buildWxMpService(keys[0], keys[1]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private WxMaService wxMaService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private WxMaProperties wxMaProperties;
 | 
			
		||||
    /**
 | 
			
		||||
     * 缓存 WxMaService 对象
 | 
			
		||||
     *
 | 
			
		||||
     * 说明同 {@link #wxMpServiceCache} 变量
 | 
			
		||||
     */
 | 
			
		||||
    private final LoadingCache<String, WxMaService> wxMaServiceCache = CacheUtils.buildAsyncReloadingCache(
 | 
			
		||||
            Duration.ofSeconds(10L),
 | 
			
		||||
            new CacheLoader<String, WxMaService>() {
 | 
			
		||||
 | 
			
		||||
                @Override
 | 
			
		||||
                public WxMaService load(String key) {
 | 
			
		||||
                    String[] keys = key.split(":");
 | 
			
		||||
                    return buildWxMaService(keys[0], keys[1]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
@@ -129,28 +157,30 @@ public class SocialClientServiceImpl implements SocialClientService {
 | 
			
		||||
        return request;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // =================== 微信公众号独有 ===================
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @SneakyThrows
 | 
			
		||||
    public WxJsapiSignature createWxMpJsapiSignature(Integer userType, String url) {
 | 
			
		||||
        WxMpService mpService = buildMpService(userType);
 | 
			
		||||
        return mpService.createJsapiSignature(url);
 | 
			
		||||
        WxMpService service = getWxMpService(userType);
 | 
			
		||||
        return service.createJsapiSignature(url);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建 clientId + clientSecret 对应的 WxMpService 对象
 | 
			
		||||
     * 获得 clientId + clientSecret 对应的 WxMpService 对象
 | 
			
		||||
     *
 | 
			
		||||
     * @param userType 用户类型
 | 
			
		||||
     * @return WxMpService 对象
 | 
			
		||||
     */
 | 
			
		||||
    private WxMpService buildMpService(Integer userType) {
 | 
			
		||||
    private WxMpService getWxMpService(Integer userType) {
 | 
			
		||||
        // 第一步,查询 DB 的配置项,获得对应的 WxMpService 对象
 | 
			
		||||
        SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
 | 
			
		||||
                SocialTypeEnum.WECHAT_MP.getType(), userType);
 | 
			
		||||
        if (client != null && Objects.equals(client.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
 | 
			
		||||
            return mpServiceCache.getUnchecked(client.getClientId() + ":" + client.getClientSecret());
 | 
			
		||||
            return wxMpServiceCache.getUnchecked(client.getClientId() + ":" + client.getClientSecret());
 | 
			
		||||
        }
 | 
			
		||||
        // 第二步,不存在 DB 配置项,则使用 application-*.yaml 对应的 WxMpService 对象
 | 
			
		||||
        return mpService;
 | 
			
		||||
        return wxMpService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -160,11 +190,11 @@ public class SocialClientServiceImpl implements SocialClientService {
 | 
			
		||||
     * @param clientSecret 微信公众号 secret
 | 
			
		||||
     * @return WxMpService 对象
 | 
			
		||||
     */
 | 
			
		||||
    private WxMpService buildMpService(String clientId, String clientSecret) {
 | 
			
		||||
    private WxMpService buildWxMpService(String clientId, String clientSecret) {
 | 
			
		||||
        // 第一步,创建 WxMpRedisConfigImpl 对象
 | 
			
		||||
        WxMpRedisConfigImpl configStorage = new WxMpRedisConfigImpl(
 | 
			
		||||
                new RedisTemplateWxRedisOps(stringRedisTemplate),
 | 
			
		||||
                mpProperties.getConfigStorage().getKeyPrefix());
 | 
			
		||||
                wxMpProperties.getConfigStorage().getKeyPrefix());
 | 
			
		||||
        configStorage.setAppId(clientId);
 | 
			
		||||
        configStorage.setSecret(clientSecret);
 | 
			
		||||
 | 
			
		||||
@@ -174,4 +204,55 @@ public class SocialClientServiceImpl implements SocialClientService {
 | 
			
		||||
        return service;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // =================== 微信小程序独有 ===================
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public WxMaPhoneNumberInfo getWxMaPhoneNumberInfo(Integer userType, String phoneCode) {
 | 
			
		||||
        WxMaService service = getWxMaService(userType);
 | 
			
		||||
        try {
 | 
			
		||||
            return service.getUserService().getPhoneNoInfo(phoneCode);
 | 
			
		||||
        } catch (WxErrorException e) {
 | 
			
		||||
            log.error("[getPhoneNoInfo][userType({}) phoneCode({}) 获得手机号失败]", userType, phoneCode, e);
 | 
			
		||||
            throw exception(SOCIAL_APP_WEIXIN_MINI_APP_PHONE_CODE_ERROR);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得 clientId + clientSecret 对应的 WxMpService 对象
 | 
			
		||||
     *
 | 
			
		||||
     * @param userType 用户类型
 | 
			
		||||
     * @return WxMpService 对象
 | 
			
		||||
     */
 | 
			
		||||
    private WxMaService getWxMaService(Integer userType) {
 | 
			
		||||
        // 第一步,查询 DB 的配置项,获得对应的 WxMaService 对象
 | 
			
		||||
        SocialClientDO client = socialClientMapper.selectBySocialTypeAndUserType(
 | 
			
		||||
                SocialTypeEnum.WECHAT_MINI_APP.getType(), userType);
 | 
			
		||||
        if (client != null && Objects.equals(client.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
 | 
			
		||||
            return wxMaServiceCache.getUnchecked(client.getClientId() + ":" + client.getClientSecret());
 | 
			
		||||
        }
 | 
			
		||||
        // 第二步,不存在 DB 配置项,则使用 application-*.yaml 对应的 WxMaService 对象
 | 
			
		||||
        return wxMaService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建 clientId + clientSecret 对应的 WxMaService 对象
 | 
			
		||||
     *
 | 
			
		||||
     * @param clientId 微信小程序 appId
 | 
			
		||||
     * @param clientSecret 微信小程序 secret
 | 
			
		||||
     * @return WxMaService 对象
 | 
			
		||||
     */
 | 
			
		||||
    private WxMaService buildWxMaService(String clientId, String clientSecret) {
 | 
			
		||||
        // 第一步,创建 WxMaRedisBetterConfigImpl 对象
 | 
			
		||||
        WxMaRedisBetterConfigImpl configStorage = new WxMaRedisBetterConfigImpl(
 | 
			
		||||
                new RedisTemplateWxRedisOps(stringRedisTemplate),
 | 
			
		||||
                wxMaProperties.getConfigStorage().getKeyPrefix());
 | 
			
		||||
        configStorage.setAppid(clientId);
 | 
			
		||||
        configStorage.setSecret(clientSecret);
 | 
			
		||||
 | 
			
		||||
        // 第二步,创建 WxMpService 对象
 | 
			
		||||
        WxMaService service = new WxMaServiceImpl();
 | 
			
		||||
        service.setWxMaConfig(configStorage);
 | 
			
		||||
        return service;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user