From ddf01f2f49282a11d815599e3bb68b601e0818c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BA=AA=E5=AF=92?= <2533659732@qq.com> Date: Thu, 21 Mar 2024 14:36:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=85=AC=E4=BC=97=E5=8F=B7?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E6=B6=88=E6=81=AF=E5=8A=9F=E8=83=BD=E5=AF=B9?= =?UTF-8?q?=E6=8E=A5=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application.yml | 15 +++- ...onfig.java => WeChatAppletChatConfig.java} | 6 +- .../config/WeChatOfficialAccountConfig.java | 36 ++++++++++ .../com/xinelu/common/constant/Constants.java | 47 +++++++----- .../com/xinelu/common/entity/AccessToken.java | 44 ++++++++++++ .../controller/MobileTestController.java | 22 ++++++ .../WeChatAppletCallBackController.java | 4 +- ...ChatOfficialAccountCallbackController.java | 42 +++++++++++ .../impl/WeChatAppletCallBackServiceImpl.java | 4 +- .../mobile/utils/WeChatAppletUtils.java | 71 +++++++++++++++++++ .../utils/WeChatOfficialAccountUtils.java | 71 +++++++++++++++++++ 11 files changed, 337 insertions(+), 25 deletions(-) rename postdischarge-common/src/main/java/com/xinelu/common/config/{AppletChatConfig.java => WeChatAppletChatConfig.java} (87%) create mode 100644 postdischarge-common/src/main/java/com/xinelu/common/config/WeChatOfficialAccountConfig.java create mode 100644 postdischarge-common/src/main/java/com/xinelu/common/entity/AccessToken.java create mode 100644 postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/wechatofficialaccountcallback/WeChatOfficialAccountCallbackController.java create mode 100644 postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/WeChatAppletUtils.java create mode 100644 postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/WeChatOfficialAccountUtils.java diff --git a/postdischarge-admin/src/main/resources/application.yml b/postdischarge-admin/src/main/resources/application.yml index 8550115d..257ced72 100644 --- a/postdischarge-admin/src/main/resources/application.yml +++ b/postdischarge-admin/src/main/resources/application.yml @@ -185,8 +185,8 @@ xss: # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* -# 微信小程序参数配置信息 -applet-chat-config: +# 院后微信小程序参数配置信息 +wechat-applet-chat-config: # 微信小程序id,wxdec3416aa3d60cab applet-id: wxdc32268eca6b78f9 # 微信小程序密钥,f58e19be0380c2ebc6e9e9684c0dacce @@ -207,3 +207,14 @@ applet-chat-config: appoint-order-template-id: nUB9HRbqQXOVuTpkKBIHMgzWlNq6touzxf5QYBiMkbU # 签到成功通知模板id sign-template-id: S_c9bR4znSWpXg-6ACIMn7AkaR11dzo113XM8w4CKz0 + +# 院后微信公众号参数配置 +wechat-official-account-config: + # 微信公众号id + official-account-app-id: wx9d87c7c73ef1ebde + # 微信公众号secret + official-account-app-secret: 20ab2c266b1da75d71e9932e7d28326e + # 微信公众号事件回调令牌 + official-account-token: Token + # 微信公众号事件回调消息加密密钥 + official-account-encoding-aes-key: xinyilu \ No newline at end of file diff --git a/postdischarge-common/src/main/java/com/xinelu/common/config/AppletChatConfig.java b/postdischarge-common/src/main/java/com/xinelu/common/config/WeChatAppletChatConfig.java similarity index 87% rename from postdischarge-common/src/main/java/com/xinelu/common/config/AppletChatConfig.java rename to postdischarge-common/src/main/java/com/xinelu/common/config/WeChatAppletChatConfig.java index b2cd5dec..d2db2da6 100644 --- a/postdischarge-common/src/main/java/com/xinelu/common/config/AppletChatConfig.java +++ b/postdischarge-common/src/main/java/com/xinelu/common/config/WeChatAppletChatConfig.java @@ -5,15 +5,15 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** - * @Description 微信小程序参数配置类 + * @Description 新医路院后微信小程序参数配置类 * @Author 纪寒 * @Date 2024-03-19 15:52:38 * @Version 1.0 */ @Data @Component -@ConfigurationProperties(prefix = "applet-chat-config") -public class AppletChatConfig { +@ConfigurationProperties(prefix = "wechat-applet-chat-config") +public class WeChatAppletChatConfig { /** * 小程序id diff --git a/postdischarge-common/src/main/java/com/xinelu/common/config/WeChatOfficialAccountConfig.java b/postdischarge-common/src/main/java/com/xinelu/common/config/WeChatOfficialAccountConfig.java new file mode 100644 index 00000000..fad78d8e --- /dev/null +++ b/postdischarge-common/src/main/java/com/xinelu/common/config/WeChatOfficialAccountConfig.java @@ -0,0 +1,36 @@ +package com.xinelu.common.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @Description 新医路院后微信公众号参数配置类 + * @Author 纪寒 + * @Date 2024-03-21 11:12:04 + * @Version 1.0 + */ +@Data +@Component +@ConfigurationProperties(prefix = "wechat-official-account-config") +public class WeChatOfficialAccountConfig { + /** + * 微信公众号id + */ + private String officialAccountAppId; + + /** + * 微信公众号secret + */ + private String officialAccountAppSecret; + + /** + * 微信公众号事件回调令牌 + */ + private String officialAccountToken; + + /** + * 微信公众号事件回调消息加密密钥 + */ + private String officialAccountEncodingAesKey; +} diff --git a/postdischarge-common/src/main/java/com/xinelu/common/constant/Constants.java b/postdischarge-common/src/main/java/com/xinelu/common/constant/Constants.java index d41889f7..0023f012 100644 --- a/postdischarge-common/src/main/java/com/xinelu/common/constant/Constants.java +++ b/postdischarge-common/src/main/java/com/xinelu/common/constant/Constants.java @@ -189,23 +189,38 @@ public class Constants { */ public static final String TASK_PARTITION_CODE = "TPC"; - /** - * 门诊患者 - */ - public static final String OUTPATIENT = "outpatient"; + /** + * 门诊患者 + */ + public static final String OUTPATIENT = "outpatient"; - /** - * 预住院 - */ - public static final String PRE_HOSPITALIZED = "prehospitalized"; + /** + * 预住院 + */ + public static final String PRE_HOSPITALIZED = "prehospitalized"; - /** - * 在院 - */ - public static final String IN_HOSPITAL = "inhospital"; + /** + * 在院 + */ + public static final String IN_HOSPITAL = "inhospital"; - /** - * 出院 - */ - public static final String DISCHARGED = "discharged"; + /** + * 出院 + */ + public static final String DISCHARGED = "discharged"; + + /** + * 院后微信小程序accessToken的redis的键前缀 + */ + public static final String WE_CHAT_APPLET_ACCESS_TOKEN = "WE_CHAT_APPLET_ACCESS_TOKEN_"; + + /** + * 院后微信公众号accessToken的redis的键前缀 + */ + public static final String WE_CHAT_OFFICIAL_ACCOUNT_ACCESS_TOKEN = "WE_CHAT_OFFICIAL_ACCOUNT_ACCESS_TOKEN_"; + + /** + * 获取微信小程序和微信公众号accessToken的url地址 + */ + public static final String WE_CHAT_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"; } diff --git a/postdischarge-common/src/main/java/com/xinelu/common/entity/AccessToken.java b/postdischarge-common/src/main/java/com/xinelu/common/entity/AccessToken.java new file mode 100644 index 00000000..652a145a --- /dev/null +++ b/postdischarge-common/src/main/java/com/xinelu/common/entity/AccessToken.java @@ -0,0 +1,44 @@ +package com.xinelu.common.entity; + +import com.alibaba.fastjson2.annotation.JSONField; +import lombok.Data; + +import java.io.Serializable; + +/** + * @Description 微信小程序和微信公众号accessToken信息实体类 + * @Author 纪寒 + * @Date 2024-03-21 14:00:10 + * @Version 1.0 + */ +@Data +public class AccessToken implements Serializable { + private static final long serialVersionUID = -7751995012730354177L; + /** + * accessToken值 + */ + @JSONField(name = "access_token") + private String accessToken; + + /** + * access_token有效时间,有效时间为7200秒 + */ + @JSONField(name = "expires_in") + private String expiresIn; + + /** + * 错误状态码 + * 40001:AppSecret 错误或者 AppSecret 不属于这个小程序,请开发者确认 AppSecret 的正确性 + * 40002:请确保 grant_type 字段值为 client_credential + * 40013:不合法的 AppID,请开发者检查 AppID 的正确性,避免异常字符,注意大小写 + */ + private Integer errcode; + + /** + * 错误状态值 + * 40001:AppSecret 错误或者 AppSecret 不属于这个小程序,请开发者确认 AppSecret 的正确性 + * 40002:请确保 grant_type 字段值为 client_credential + * 40013:不合法的 AppID,请开发者检查 AppID 的正确性,避免异常字符,注意大小写 + */ + private String errmsg; +} diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/MobileTestController.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/MobileTestController.java index 8ca6acc9..ba977a84 100644 --- a/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/MobileTestController.java +++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/MobileTestController.java @@ -1,8 +1,12 @@ package com.xinelu.mobile.controller; +import com.xinelu.mobile.utils.WeChatAppletUtils; +import com.xinelu.mobile.utils.WeChatOfficialAccountUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.annotation.Resource; + /** * @Description 测试controller * @Author 纪寒 @@ -12,5 +16,23 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/testMobile") public class MobileTestController { + @Resource + private WeChatAppletUtils weChatAppletUtils; + @Resource + private WeChatOfficialAccountUtils weChatOfficialAccountUtils; + /** + * 测试获取微信小程序accessToken + */ + @RequestMapping("/getAppletAcccessToken") + public void getAppletAccessToken() { + weChatAppletUtils.getWeChatAppletAccessToken(); + } + /** + * 测试获取微信公众号accessToken + */ + @RequestMapping("/getOfficialAccountAccessToken") + public void getOfficialAccountAccessToken() { + weChatOfficialAccountUtils.getWeChatOfficialAccountAccessToken(); + } } diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/wechatappletcallback/WeChatAppletCallBackController.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/wechatappletcallback/WeChatAppletCallBackController.java index 6d7006fa..d5b17c56 100644 --- a/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/wechatappletcallback/WeChatAppletCallBackController.java +++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/wechatappletcallback/WeChatAppletCallBackController.java @@ -1,6 +1,6 @@ package com.xinelu.mobile.controller.wechatappletcallback; -import com.xinelu.common.config.AppletChatConfig; +import com.xinelu.common.config.WeChatAppletChatConfig; import com.xinelu.common.utils.aes.AesException; import com.xinelu.common.utils.aes.WXBizMsgCrypt; import com.xinelu.mobile.dto.wechatappletcallback.MessageSignDTO; @@ -26,7 +26,7 @@ import java.util.Objects; public class WeChatAppletCallBackController { @Resource - private AppletChatConfig appletChatConfig; + private WeChatAppletChatConfig appletChatConfig; @Resource private WeChatAppletCallBackService weChatAppletCallBackService; diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/wechatofficialaccountcallback/WeChatOfficialAccountCallbackController.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/wechatofficialaccountcallback/WeChatOfficialAccountCallbackController.java new file mode 100644 index 00000000..c48451dc --- /dev/null +++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/controller/wechatofficialaccountcallback/WeChatOfficialAccountCallbackController.java @@ -0,0 +1,42 @@ +package com.xinelu.mobile.controller.wechatofficialaccountcallback; + +import com.xinelu.common.config.WeChatOfficialAccountConfig; +import com.xinelu.common.utils.aes.AesException; +import com.xinelu.common.utils.aes.WXBizMsgCrypt; +import com.xinelu.mobile.dto.wechatappletcallback.MessageSignDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +/** + * @Description 院后微信公众号事件回调控制器 + * @Author 纪寒 + * @Date 2024-03-21 14:26:56 + * @Version 1.0 + */ +@Slf4j +@RestController +@RequestMapping("/postDischarge/officialAccountCallback") +public class WeChatOfficialAccountCallbackController { + @Resource + private WeChatOfficialAccountConfig weChatOfficialAccountConfig; + + /** + * 院后微信公众号回调验证方法 + * + * @param messageSignDTO 微信输入参数 + * @return 解密后的字符串 + * @throws AesException 异常信息 + */ + @GetMapping + public String getWeChatOfficialAccountCallBack(MessageSignDTO messageSignDTO) throws AesException { + WXBizMsgCrypt wxCpt = new WXBizMsgCrypt(weChatOfficialAccountConfig.getOfficialAccountToken(), weChatOfficialAccountConfig.getOfficialAccountEncodingAesKey(), weChatOfficialAccountConfig.getOfficialAccountAppId()); + String verifyMessage = wxCpt.verifyUrl(messageSignDTO.getSignature(), messageSignDTO.getTimestamp(), messageSignDTO.getNonce(), messageSignDTO.getEchostr()); + log.info("院后微信公众号回调设置验证URL成功,验证信息:verifyMessage = [{}]", verifyMessage); + return verifyMessage; + } +} + diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/wechatappletcallback/impl/WeChatAppletCallBackServiceImpl.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/wechatappletcallback/impl/WeChatAppletCallBackServiceImpl.java index 8823f23a..56c427dd 100644 --- a/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/wechatappletcallback/impl/WeChatAppletCallBackServiceImpl.java +++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/service/wechatappletcallback/impl/WeChatAppletCallBackServiceImpl.java @@ -1,6 +1,6 @@ package com.xinelu.mobile.service.wechatappletcallback.impl; -import com.xinelu.common.config.AppletChatConfig; +import com.xinelu.common.config.WeChatAppletChatConfig; import com.xinelu.common.enums.SubscribeMessageTypeEnum; import com.xinelu.common.exception.ServiceException; import com.xinelu.common.utils.DateUtils; @@ -39,7 +39,7 @@ public class WeChatAppletCallBackServiceImpl implements WeChatAppletCallBackServ @Resource private SubscribeMessageRecordMapper subscribeMessageRecordMapper; @Resource - private AppletChatConfig appletChatConfig; + private WeChatAppletChatConfig appletChatConfig; @Resource private PatientInfoMapper patientInfoMapper; @Resource diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/WeChatAppletUtils.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/WeChatAppletUtils.java new file mode 100644 index 00000000..62b2cba8 --- /dev/null +++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/WeChatAppletUtils.java @@ -0,0 +1,71 @@ +package com.xinelu.mobile.utils; + +import com.alibaba.fastjson2.JSON; +import com.xinelu.common.config.WeChatAppletChatConfig; +import com.xinelu.common.constant.Constants; +import com.xinelu.common.entity.AccessToken; +import com.xinelu.common.exception.ServiceException; +import com.xinelu.common.utils.http.HttpUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** + * @Description 院后微信小程序公共方法工具类 + * @Author 纪寒 + * @Date 2024-03-21 13:41:08 + * @Version 1.0 + */ +@Component +public class WeChatAppletUtils { + + @Resource + private RedisTemplate redisTemplate; + @Resource + private WeChatAppletChatConfig weChatAppletChatConfig; + /** + * 返回成功状态码 + */ + private static final int SUCCESS_CODE = 0; + + /** + * 获取微信小程序的accessToken值 + * + * @return 小程序accessToken值 + */ + public String getWeChatAppletAccessToken() { + String accessToken; + String accessTokenRedisKey = Constants.WE_CHAT_APPLET_ACCESS_TOKEN + "accessToken"; + //从Redis中取出accessToken + Object object = redisTemplate.opsForValue().get(accessTokenRedisKey); + if (Objects.isNull(object)) { + //没有,获取accessToken + String accessTokenUrl = Constants.WE_CHAT_ACCESS_TOKEN_URL + "&appid=" + weChatAppletChatConfig.getAppletId() + "&secret=" + weChatAppletChatConfig.getSecret(); + //发送请求 + String result = HttpUtils.sendGet(accessTokenUrl); + if (StringUtils.isBlank(result)) { + throw new ServiceException("获取微信小程序accessToken信息失败", 201); + } + AccessToken weAppletAccessToken = JSON.parseObject(result, AccessToken.class); + if (Objects.isNull(weAppletAccessToken)) { + throw new ServiceException("获取微信小程序accessToken信息失败"); + } + if (Objects.nonNull(weAppletAccessToken.getErrcode()) && weAppletAccessToken.getErrcode() != SUCCESS_CODE) { + throw new ServiceException("获取微信小程序accessToken信息失败,失败信息为:" + weAppletAccessToken.getErrmsg(), 201); + } + if (StringUtils.isBlank(weAppletAccessToken.getAccessToken())) { + throw new ServiceException("微信小程序accessToken信息为空"); + } + accessToken = weAppletAccessToken.getAccessToken(); + //存入Redis中 + redisTemplate.opsForValue().set(accessTokenRedisKey, accessToken, 3600, TimeUnit.SECONDS); + } else { + accessToken = (String) object; + } + return accessToken; + } +} diff --git a/postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/WeChatOfficialAccountUtils.java b/postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/WeChatOfficialAccountUtils.java new file mode 100644 index 00000000..ccfc4b0a --- /dev/null +++ b/postdischarge-mobile/src/main/java/com/xinelu/mobile/utils/WeChatOfficialAccountUtils.java @@ -0,0 +1,71 @@ +package com.xinelu.mobile.utils; + +import com.alibaba.fastjson2.JSON; +import com.xinelu.common.config.WeChatOfficialAccountConfig; +import com.xinelu.common.constant.Constants; +import com.xinelu.common.entity.AccessToken; +import com.xinelu.common.exception.ServiceException; +import com.xinelu.common.utils.http.HttpUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** + * @Description 院后公众号公众方法工具类 + * @Author 纪寒 + * @Date 2024-03-21 13:42:31 + * @Version 1.0 + */ +@Component +public class WeChatOfficialAccountUtils { + + @Resource + private RedisTemplate redisTemplate; + @Resource + private WeChatOfficialAccountConfig weChatOfficialAccountConfig; + /** + * 返回成功状态码 + */ + private static final int SUCCESS_CODE = 0; + + /** + * 获取院后微信公众号accessToken + * + * @return 微信公众号的accessToken + */ + public String getWeChatOfficialAccountAccessToken() { + String accessToken; + String accessTokenRedisKey = Constants.WE_CHAT_OFFICIAL_ACCOUNT_ACCESS_TOKEN + "accessToken"; + //从Redis中取出accessToken + Object object = redisTemplate.opsForValue().get(accessTokenRedisKey); + if (Objects.isNull(object)) { + //没有,获取accessToken + String accessTokenUrl = Constants.WE_CHAT_ACCESS_TOKEN_URL + "&appid=" + weChatOfficialAccountConfig.getOfficialAccountAppId() + "&secret=" + weChatOfficialAccountConfig.getOfficialAccountAppSecret(); + //发送请求 + String result = HttpUtils.sendGet(accessTokenUrl); + if (StringUtils.isBlank(result)) { + throw new ServiceException("获取微信公众号accessToken信息失败", 201); + } + AccessToken officialAccountAccessToken = JSON.parseObject(result, AccessToken.class); + if (Objects.isNull(officialAccountAccessToken)) { + throw new ServiceException("获取微信公众号accessToken信息失败"); + } + if (Objects.nonNull(officialAccountAccessToken.getErrcode()) && officialAccountAccessToken.getErrcode() != SUCCESS_CODE) { + throw new ServiceException("获取微信公众号accessToken信息失败,失败信息为:" + officialAccountAccessToken.getErrmsg(), 201); + } + if (StringUtils.isBlank(officialAccountAccessToken.getAccessToken())) { + throw new ServiceException("微信公众号accessToken信息为空"); + } + accessToken = officialAccountAccessToken.getAccessToken(); + //存入Redis中 + redisTemplate.opsForValue().set(accessTokenRedisKey, accessToken, 3600, TimeUnit.SECONDS); + } else { + accessToken = (String) object; + } + return accessToken; + } +}