From b557055f33670ac6a064953de5941c793aeef2e2 Mon Sep 17 00:00:00 2001 From: "382696293@qq.com" <382696293@qq.com> Date: Tue, 19 Dec 2023 09:30:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=98=AF=E5=90=A6=E5=85=B3=E6=B3=A8=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E5=85=AC=E4=BC=97=E5=8F=B7=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/core/constant/CacheConstants.java | 9 ++- .../config/properties/WxConfig.java | 27 +++++++- .../vo/OfficialAccountUserDetailRet.java | 11 ++++ .../miniProgram/utils/HttpClientUtils.java | 62 ++++++++++++++++++- .../miniProgram/utils/MiniProgramUtils.java | 55 ++++++++-------- 5 files changed, 133 insertions(+), 31 deletions(-) diff --git a/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/constant/CacheConstants.java b/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/constant/CacheConstants.java index 4a644a3..3f403b2 100644 --- a/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/constant/CacheConstants.java +++ b/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/constant/CacheConstants.java @@ -63,9 +63,14 @@ public class CacheConstants public static final String WX_SESSION_KEY_CACHE = "wx_session_key:"; /** - * 微信小程序 access_token + * 微信小程序 access_token 缓存 + */ + public static final String WX_MINI_PROGRAM_ACCESS_TOKEN_CACHE = "wx_mini_program_access_token_cache"; + + /** + * 微信公众号 access_token 缓存 */ - public static final String WX_ACCESS_TOKEN_CACHE = "wx_access_token_cache:"; + public static final String WX_OFFICIAL_ACCOUNT_ACCESS_TOKEN_CACHE = "wx_official_account_access_token_cache"; /** * 微信小程序 access_token diff --git a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/config/properties/WxConfig.java b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/config/properties/WxConfig.java index 0c78530..801dee9 100644 --- a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/config/properties/WxConfig.java +++ b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/config/properties/WxConfig.java @@ -14,6 +14,16 @@ import org.springframework.context.annotation.Configuration; @ConfigurationProperties(prefix = "wx.config") public class WxConfig { + /** + * 微信公众号 appid + */ + private String officialAccountAppid; + + /** + * 微信公众号 appKey + */ + private String officialAccountAppSecret; + /** * jscode2session * 通过 code 去微信服务器换取 openid 和 session_key @@ -32,7 +42,6 @@ public class WxConfig { private String ObtainUserInfoByOpenidUrl; - public String getLoginUrl() { return loginUrl; } @@ -72,4 +81,20 @@ public class WxConfig { public void setObtainUserInfoByOpenidUrl(String obtainUserInfoByOpenidUrl) { ObtainUserInfoByOpenidUrl = obtainUserInfoByOpenidUrl; } + + public String getOfficialAccountAppid() { + return officialAccountAppid; + } + + public void setOfficialAccountAppid(String officialAccountAppid) { + this.officialAccountAppid = officialAccountAppid; + } + + public String getOfficialAccountAppSecret() { + return officialAccountAppSecret; + } + + public void setOfficialAccountAppSecret(String officialAccountAppSecret) { + this.officialAccountAppSecret = officialAccountAppSecret; + } } diff --git a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/domain/vo/OfficialAccountUserDetailRet.java b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/domain/vo/OfficialAccountUserDetailRet.java index 160f1b7..48b5fcb 100644 --- a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/domain/vo/OfficialAccountUserDetailRet.java +++ b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/domain/vo/OfficialAccountUserDetailRet.java @@ -1,5 +1,7 @@ package com.flossom.miniProgram.domain.vo; +import com.flossom.common.core.utils.StringUtils; + import java.util.List; /** @@ -46,6 +48,15 @@ public class OfficialAccountUserDetailRet { this.errmsg = errmsg; } + public Boolean isContainUnionid(String unionid) { + for (userInfoList userInfoList : this.getUser_info_list()) { + if (StringUtils.equals(userInfoList.getUnionid(), unionid)) { + return true; + } + } + return false; + } + class userInfoList { private Integer subscribe; private String openid; diff --git a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/utils/HttpClientUtils.java b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/utils/HttpClientUtils.java index 5a9fdb0..170557c 100644 --- a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/utils/HttpClientUtils.java +++ b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/utils/HttpClientUtils.java @@ -60,7 +60,11 @@ public class HttpClientUtils { client = HttpClients.custom().setConnectionManager(cm).build(); } - public static String postParameters(String url, String parameterStr) throws ConnectTimeoutException, SocketTimeoutException, Exception { + public static String postJsonParameters(String url, String parameterStr) throws Exception { + return postJson(url, parameterStr, charset, connTimeout, readTimeout); + } + + public static String postParameters(String url, String parameterStr) throws Exception { return post(url, parameterStr, "application/x-www-form-urlencoded", charset, connTimeout, readTimeout); } @@ -97,6 +101,62 @@ public class HttpClientUtils { return get(uri.toString(), charset, null, null); } + /** + * 发送一个 Post 请求, 使用指定的字符集编码. + * + * @param url + * @param body RequestBody + * @param charset 编码 + * @param connTimeout 建立链接超时时间,毫秒. + * @param readTimeout 响应超时时间,毫秒. + * @return ResponseBody, 使用指定的字符集编码. + * @throws ConnectTimeoutException 建立链接超时异常 + * @throws SocketTimeoutException 响应超时 + * @throws Exception + */ + public static String postJson(String url, String body, String charset, Integer connTimeout, Integer readTimeout) throws Exception { + HttpClient client = null; + HttpPost post = new HttpPost(url); + String result = ""; + try { + if (StringUtils.isNotBlank(body)) { + HttpEntity entity = new StringEntity(body, ContentType.APPLICATION_JSON); + post.setEntity(entity); + } + + // 设置参数 + RequestConfig.Builder customReqConf = RequestConfig.custom(); + if (connTimeout != null) { + customReqConf.setConnectTimeout(connTimeout); + } + if (readTimeout != null) { + customReqConf.setSocketTimeout(readTimeout); + } + post.setConfig(customReqConf.build()); + + HttpResponse res; + if (url.startsWith("https")) { + // 执行 Https 请求. + client = createSSLInsecureClient(); + res = client.execute(post); + } else { + // 执行 Http 请求. + client = HttpClientUtils.client; + res = client.execute(post); + } + result = EntityUtils.toString(res.getEntity(), charset); + } catch (Exception ex) { + log.error("HttpClient request error!", ex); + throw ex; + } finally { + post.releaseConnection(); + if (url.startsWith("https") && client != null && client instanceof CloseableHttpClient) { + ((CloseableHttpClient) client).close(); + } + } + return result; + } + /** * 发送一个 Post 请求, 使用指定的字符集编码. * diff --git a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/utils/MiniProgramUtils.java b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/utils/MiniProgramUtils.java index b78f7c7..205e873 100644 --- a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/utils/MiniProgramUtils.java +++ b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/utils/MiniProgramUtils.java @@ -102,23 +102,21 @@ public class MiniProgramUtils { /** * 获取 acceess_token + * 微信小程序 / 微信公众号 获取地址是一样得,但是 要用各自得 appid 和 secret + *

+ * 将 access_token 保存在 redis,官方定义说 access_token 的有效期暂定为 2个小时, + * 使用注意事项: 从 redis 获取 access_token,存在则未过期,不存在则过期了,重新获取 access_token * * @return * @throws Exception */ - public static String getAccessToken() throws Exception { - - /** - * TODO: 将 access_token 保存在 redis,官方定义说 access_token 的有效期暂定为 2个小时,使用注意事项: - * 1、从 redis 获取 access_token,存在则未过期,不存在则过期了,重新获取 access_token - */ - String accessToken = redisService.getCacheObject(CacheConstants.WX_ACCESS_TOKEN_CACHE); + public static String getAccessToken(String appid, String secret, String cacheKey) throws Exception { + String accessToken = redisService.getCacheObject(cacheKey); if (StringUtils.isBlank(accessToken)) { // 获取 access_token Map params = new HashMap(); - WxParameterSetting wxParameterSetting = wxParameterSettingMapper.selectWxParameterSettingById(1L); - params.put("appid", wxParameterSetting.getAppid()); - params.put("secret", wxParameterSetting.getAppkey()); + params.put("appid", appid); + params.put("secret", secret); params.put("grant_type", "client_credential"); String result = HttpClientUtils.getParameters(wxConfig.getAccessTokenUrl(), params); logger.info("请求微信服务器获取access_token返回结果:{}", result); @@ -128,7 +126,7 @@ public class MiniProgramUtils { return null; } // 保存缓存 - redisService.setCacheObject(CacheConstants.WX_ACCESS_TOKEN_CACHE, + redisService.setCacheObject(cacheKey, wxAccessTokenRet.getAccess_token(), CacheConstants.WX_ACCESS_TOKEN_EXPIRATION, TimeUnit.MINUTES); return wxAccessTokenRet.getAccess_token(); } @@ -136,6 +134,8 @@ public class MiniProgramUtils { } /** + * 注意 要使用 微信小程序得 appid 和 appKey + * * @param code * @return

* errcode number 错误码 @@ -147,7 +147,8 @@ public class MiniProgramUtils { * countryCode string 区号 */ public static String getPhone(String code) throws Exception { - String accessToken = getAccessToken(); + WxParameterSetting wxParameterSetting = wxParameterSettingMapper.selectWxParameterSettingById(1L); + String accessToken = getAccessToken(wxParameterSetting.getAppid(), wxParameterSetting.getAppkey(), CacheConstants.WX_MINI_PROGRAM_ACCESS_TOKEN_CACHE); if (StringUtils.isBlank(accessToken)) { throw new ServiceException("获取用户手机号码失败"); } @@ -166,7 +167,7 @@ public class MiniProgramUtils { * @throws Exception */ public static OfficialAccountUserRet obtainWxOfficialAccountUser(String nextOpenid) throws Exception { - String accessToken = getAccessToken(); + String accessToken = getAccessToken(wxConfig.getOfficialAccountAppid(), wxConfig.getOfficialAccountAppSecret(), CacheConstants.WX_OFFICIAL_ACCOUNT_ACCESS_TOKEN_CACHE); if (StringUtils.isBlank(accessToken)) { logger.error("获取关注微信公众号用户列表失败,获取accessToken失败!"); throw new ServiceException("操作失败"); @@ -180,7 +181,7 @@ public class MiniProgramUtils { String result = HttpClientUtils.getParameters(wxConfig.getObtainWxOfficialAccountUserUrl(), params); logger.info("请求微信服务器获取关注微信公众号的用户列表:{}", result); OfficialAccountUserRet officialAccountUserRet = JSON.parseObject(result, OfficialAccountUserRet.class); - if (officialAccountUserRet.getErrcode() != 0) { + if (officialAccountUserRet.getErrcode() != null) { logger.error("获取 关注微信公众号的用户列表 失败: {}", officialAccountUserRet.getErrmsg()); throw new ServiceException("操作失败"); } @@ -192,18 +193,19 @@ public class MiniProgramUtils { * TODO: officialAccountUserReqList 最多支持 100 条 */ public static OfficialAccountUserDetailRet ObtainUserInfoByOpenid(List officialAccountUserReqList) throws Exception { - String accessToken = getAccessToken(); + String accessToken = getAccessToken(wxConfig.getOfficialAccountAppid(), wxConfig.getOfficialAccountAppSecret(), CacheConstants.WX_OFFICIAL_ACCOUNT_ACCESS_TOKEN_CACHE); if (StringUtils.isBlank(accessToken)) { logger.error("获取关注微信公众号用户的unionid,获取accessToken失败!"); throw new ServiceException("操作失败"); } - Map params = new HashMap(); - params.put("user_list", JSON.toJSONString(officialAccountUserReqList)); - String result = HttpClientUtils.postParameters(wxConfig.getObtainUserInfoByOpenidUrl() + "access_token=" + accessToken, params); + Map params = new HashMap(); + params.put("user_list", officialAccountUserReqList); +// String result = HttpClientUtils.postJsonParameters(wxConfig.getObtainUserInfoByOpenidUrl() + "?access_token=" + accessToken, JSON.toJSONString(params)); + String result = HttpClientUtils.postParameters(wxConfig.getObtainUserInfoByOpenidUrl() + "?access_token=" + accessToken, JSON.toJSONString(params)); logger.info("请求微信服务器获获取 关注微信公众号用户的 unionid列表:{}", result); OfficialAccountUserDetailRet officialAccountUserDetailRet = JSON.parseObject(result, OfficialAccountUserDetailRet.class); - if (officialAccountUserDetailRet.getErrcode() != 0) { + if (officialAccountUserDetailRet.getErrcode() != null) { logger.error("获取 关注微信公众号的用户列表 失败: {}", officialAccountUserDetailRet.getErrmsg()); throw new ServiceException("操作失败"); } @@ -221,10 +223,6 @@ public class MiniProgramUtils { while (true) { // 1、获取关注微信公众号的用户列表 OfficialAccountUserRet officialAccountUserRet = obtainWxOfficialAccountUser(null); - if (officialAccountUserRet.getErrcode() != 0) { - logger.error("获取微信用户列表失败: {}", officialAccountUserRet.getErrmsg()); - throw new ServiceException("获取微信用户列表失败"); - } if (officialAccountUserRet.getCount() == null || officialAccountUserRet.getCount() == 0) { return false; } @@ -234,13 +232,13 @@ public class MiniProgramUtils { logger.info("微信公众号关注列表:{}", openidList); // 2、获取关注微信公众号的unionid - int pageSize = 100; - int page = (int) Math.ceil(officialAccountUserRet.getCount() / pageSize); + int pageSize = 10; + int page = officialAccountUserRet.getTotal() % pageSize == 0 ? officialAccountUserRet.getTotal() / pageSize : officialAccountUserRet.getTotal() / pageSize + 1; if (page > 0) { List pageOpenidList = officialAccountUserRet.getOpenidList(); for (int pageNo = 1; pageNo <= page; pageNo++) { // 构建分页集合 - List pageList = pageOpenidList.stream().skip((pageNo - 1) * 100).limit(pageSize).collect(Collectors.toList()); + List pageList = pageOpenidList.stream().skip((pageNo - 1) * pageSize).limit(pageSize).collect(Collectors.toList()); // 获取 unionid 集合 List officialAccountUserReqList = new ArrayList<>(); for (String openid : pageList) { @@ -250,9 +248,12 @@ public class MiniProgramUtils { OfficialAccountUserDetailRet officialAccountUserDetailRet = ObtainUserInfoByOpenid(officialAccountUserReqList); // 3、判断当前unionid是否在关注者列表 - return officialAccountUserDetailRet.getUser_info_list().contains(unionId); + if (officialAccountUserDetailRet.isContainUnionid(unionId)) { + return true; + } } } + // 4、 查完全部,未找到退出 if (StringUtils.isBlank(nextOpenid) || officialAccountUserRet.getTotal() == currentTotal) { break;