微信公众号模板消息功能对接开发
This commit is contained in:
parent
6341f71a25
commit
ddf01f2f49
@ -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
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -208,4 +208,19 @@ public class Constants {
|
||||
* 出院
|
||||
*/
|
||||
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";
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<String, Object> 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;
|
||||
}
|
||||
}
|
||||
@ -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<String, Object> 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;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user