|
@@ -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 StringRedisTemplate stringRedisTemplate; // WxMpService 需要使用到,所以在 Service 注入了它
|
|
|
+ private WxMpProperties wxMpProperties;
|
|
|
@Resource
|
|
|
- private WxMpProperties mpProperties;
|
|
|
+ private StringRedisTemplate stringRedisTemplate; // WxMpService 需要使用到,所以在 Service 注入了它
|
|
|
/**
|
|
|
* 缓存 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;
|
|
|
+ }
|
|
|
+
|
|
|
}
|