微信小程序订阅消息升级,以前的消息模板不适合使用
优采云 发布时间: 2021-08-01 22:09微信小程序订阅消息升级,以前的消息模板不适合使用
微信小程序订阅消息更新,之前的消息模板不适合使用
官方文档微信官方文档
要求
使用小程序开启直播讲座,学生可以预约,已经预约的学生会在直播开始前发送提醒和直播开始提醒
整体流程
1、模板由产品在微信小程序中设计,模板id和内容给前后端
2、前端在小程序页面发起消息订阅授权。用户同意授权后,微信返回的templateIds传递给后端
3、后端保存templateIds并组装相应的内容,保存到数据库中
4、使用定时器查询要发送的数据并发送给用户(广播前提醒)
5、用户广播,发送启动提醒
后端关键设计及代码
定义模板
public interface ConstantTemplate {
/**
* 提前提醒
*/
String CLOUD_PREACH_TEMPLATE_ID = "xxxxxxxxxxxxxx";
String CLOUD_PREACH_TEMPLATE_DATA = "{\"time1\":{\"value\":\"%s\"},\"thing2\":{\"value\":\"%s\"},\"thing3\":{\"value\":\"%s\"}}";
/**
* 开播提醒
*/
String INTERVIEW_NOTICE_TEMPLATE_ID = "xxxxxxxxxxxxxxxx";
String INTERVIEW_NOTICE_TEMPLATE_DATA ="{\"thing1\":{\"value\":\"%s\"},\"thing2\":{\"value\":\"%s\"},\time3\":{\"value\":\"%s\"},\"thing4\":{\"value\":\"%s\"},\"thing5\":{\"value\":\"%s\"}}";
}
@Getter
public enum WxMiniMsgTemplateEnum {
/**
* 微信小程序消息模板
*/
CLOUD_PREACH_TEMPLATE(CLOUD_PREACH_TEMPLATE_ID, CLOUD_PREACH_TEMPLATE_DATA),
INTERVIEW_NOTICE_TEMPLATE(INTERVIEW_NOTICE_TEMPLATE_ID, INTERVIEW_NOTICE_TEMPLATE_DATA);
private final String id;
private final String data;
WxMiniMsgTemplateEnum(String id, String data) {
this.id = id;
this.data = data;
}
public static String getDataById(String id) {
return Arrays.stream(WxMiniMsgTemplateEnum.values()).filter(r -> r.getId().equals(id)).findFirst().map(WxMiniMsgTemplateEnum::getData).orElse(null);
}
}
保存消息
for (String templateId : dto.getTemplateIds()) {
//发送小程序订阅消息
XyWxMiniMsgDTO wxMsgDTO = new XyWxMiniMsgDTO();
wxMsgDTO.setPage(dto.getPage());
wxMsgDTO.setEndpoint(com.xyedu.sims.common.enums.SourceTypeEnum.STUDENT_MINI.getCode());
wxMsgDTO.setLang("zh_CN");
wxMsgDTO.setMiniprogramState(ConstantUtil.MiniprogramState);
wxMsgDTO.setTouser(social.getOpenId());
LocalDateTime sendTime = topicInfo.getStartTime();
LocalDateTime pastTime = topicInfo.getEndTime();
//提前20分钟发送通知
wxMsgDTO.setSendTime(sendTime.minusMinutes(20));
wxMsgDTO.setPastTime(pastTime);
String date = DateUtil.getDefaultFormatDate(DateUtil.localDateTimeToDate(topicInfo.getStartTime()));
//组装模板数据
String data = WxMiniMsgTemplateEnum.getDataById(templateId);
if (ToolUtil.isNotEmpty(data)) {
data = String.format(data, date, StrUtil.subWithLength(topicInfo.getTitle(), 0, 20), userCache.getRealName() + "同学,云宣讲即将开始~");
wxMsgDTO.setData(JSONUtil.toJsonStr(data));
}
wxMsgDTO.setTemplateId(templateId);
XyWxMiniMsg miniMsg = BeanUtil.copy(wxMsgDTO, XyWxMiniMsg.class);
//保存至数据库
remoteXyWxMiniMsgService.add(miniMsg);
}
包裹发送工具
@Slf4j
public class WxMiniMsgUtil {
//官方文档: https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html
private static final String WX_MINI_MSG_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=";
public static Object send(String accessToken, XyWxMiniMsgDTO dto) {
String url = WX_MINI_MSG_URL + accessToken;
Map reqBody = new HashMap();
reqBody.put("touser", dto.getTouser());
reqBody.put("template_id", dto.getTemplateId());
reqBody.put("miniprogram_state", dto.getMiniprogramState());
reqBody.put("lang", dto.getLang());
reqBody.put("page", dto.getPage());
reqBody.put("data", JSONUtil.parseObj(dto.getData()));
try {
return HttpRequest.post(url)
.body(JSONUtil.toJsonStr(reqBody))
.timeout(5000)
.execute()
.body();
} catch (Exception e) {
log.error("send wx mini msg occur an exception,e={}", e.getMessage());
return null;
}
}
}
使用定时器发送,定时器每3分钟执行一次查询,查询未发送或发送失败的消息。如果超过时间,发送状态将设置为过期
@Getter
public enum WxMiniMsgSendStatusEnum {
/**
*
*/
SENDING(0, "未发送"),
SEND_SUCCESS(1, "发送成功"),
SEND_FAIL(2, "发送失败"),
OVERDUE(3,"过期");
private Integer code;
private String msg;
WxMiniMsgSendStatusEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public static String getMsg(Object code) {
if (code == null) {
return null;
}
return Arrays.stream(values()).filter(e -> e.getCode().equals(code)).findFirst().map(e -> e.getMsg()).orElse("");
}
}
@Override
public ReturnT execute(String param) throws Exception {
log.debug("[send wx mini msg]-start");
XyWxMiniMsgQueryDTO dto = new XyWxMiniMsgQueryDTO();
dto.setEndpoint(SourceTypeEnum.STUDENT_MINI.getCode());
//从数据库中获取应发送的数据列表
List list = remoteXyWxMiniMsgService.list(dto);
if (CollectionUtil.isNotEmpty(list)) {
log.debug("[send wx mini msg]-query list,list.size={}", list.size());
final WxMaService wxService = WxMaConfiguration.getMaService();
String accessToken = wxService.getAccessToken();
for (XyWxMiniMsg msg : list) {
XyWxMiniMsgDTO msgDTO = BeanUtil.copy(msg, XyWxMiniMsgDTO.class);
//通知微信发送订阅消息
Object response = WxMiniMsgUtil.send(accessToken, msgDTO);
if (ToolUtil.isNotEmpty(response)) {
msg.setResponse(response.toString());
JSONObject object = JSONUtil.parseObj(response);
//处理微信响应信息
if (object.containsKey("errcode")
&& NumberUtil.isNumber(object.get("errcode").toString())
&& Integer.valueOf(object.get("errcode").toString()) == 0) {
msg.setSendStatus(WxMiniMsgSendStatusEnum.SEND_SUCCESS.getCode());
} else if (object.containsKey("errcode")
&& NumberUtil.isNumber(object.get("errcode").toString())
&& Integer.valueOf(object.get("errcode").toString()) == 42001) {
log.error("[send wx mini msg]-response fail,refresh accessToken={}", response);
msg.setSendStatus(WxMiniMsgSendStatusEnum.SEND_FAIL.getCode());
WxMaConfiguration.getMaService().getAccessToken(true);
} else {
msg.setSendStatus(WxMiniMsgSendStatusEnum.SEND_FAIL.getCode());
log.error("[send wx mini msg]-response fail,response={}", response);
}
} else {
msg.setSendStatus(WxMiniMsgSendStatusEnum.SEND_FAIL.getCode());
log.error("[send wx mini msg]-response empty,may be catch exception,params[accessToken={}\n,msgDTO={}]", accessToken, msgDTO);
}
}
remoteXyWxMiniMsgService.updateBatch(list);
}
log.debug("[send wx mini msg]-finish");
return ReturnT.SUCCESS;
}
要求点 5 尚未完成。思路大概是在组装提前提醒模板的时候把开机提醒消息保存到数据库中,用templateId+演示的id作为唯一标识,在数据库中查询广播开始时要发送的消息,最后直接通过工具类发送