微信小程序訂閱消息升級,以前的消息模板不適合使用
優(yōu)采云 發(fā)布時(shí)間: 2021-08-01 22:09微信小程序訂閱消息升級,以前的消息模板不適合使用
微信小程序訂閱消息更新,之前的消息模板不適合使用
官方文檔微信官方文檔
要求
使用小程序開(kāi)啟直播講座,學(xué)生可以預約,已經(jīng)預約的學(xué)生會(huì )在直播開(kāi)始前發(fā)送提醒和直播開(kāi)始提醒
整體流程
1、模板由產(chǎn)品在微信小程序中設計,模板id和內容給前后端
2、前端在小程序頁(yè)面發(fā)起消息訂閱授權。用戶(hù)同意授權后,微信返回的templateIds傳遞給后端
3、后端保存templateIds并組裝相應的內容,保存到數據庫中
4、使用定時(shí)器查詢(xún)要發(fā)送的數據并發(fā)送給用戶(hù)(廣播前提醒)
5、用戶(hù)廣播,發(fā)送啟動(dòng)提醒
后端關(guān)鍵設計及代碼
定義模板
public interface ConstantTemplate {
/**
* 提前提醒
*/
String CLOUD_PREACH_TEMPLATE_ID = "xxxxxxxxxxxxxx";
String CLOUD_PREACH_TEMPLATE_DATA = "{\"time1\":{\"value\":\"%s\"},\"thing2\":{\"value\":\"%s\"},\"thing3\":{\"value\":\"%s\"}}";
/**
* 開(kāi)播提醒
*/
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()) {
//發(fā)送小程序訂閱消息
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分鐘發(fā)送通知
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() + "同學(xué),云宣講即將開(kāi)始~");
wxMsgDTO.setData(JSONUtil.toJsonStr(data));
}
wxMsgDTO.setTemplateId(templateId);
XyWxMiniMsg miniMsg = BeanUtil.copy(wxMsgDTO, XyWxMiniMsg.class);
//保存至數據庫
remoteXyWxMiniMsgService.add(miniMsg);
}
包裹發(fā)送工具
@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;
}
}
}
使用定時(shí)器發(fā)送,定時(shí)器每3分鐘執行一次查詢(xún),查詢(xún)未發(fā)送或發(fā)送失敗的消息。如果超過(guò)時(shí)間,發(fā)送狀態(tài)將設置為過(guò)期
@Getter
public enum WxMiniMsgSendStatusEnum {
/**
*
*/
SENDING(0, "未發(fā)送"),
SEND_SUCCESS(1, "發(fā)送成功"),
SEND_FAIL(2, "發(fā)送失敗"),
OVERDUE(3,"過(guò)期");
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());
//從數據庫中獲取應發(fā)送的數據列表
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);
//通知微信發(fā)送訂閱消息
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;
}
要求點(diǎn) 5 尚未完成。思路大概是在組裝提前提醒模板的時(shí)候把開(kāi)機提醒消息保存到數據庫中,用templateId+演示的id作為唯一標識,在數據庫中查詢(xún)廣播開(kāi)始時(shí)要發(fā)送的消息,最后直接通過(guò)工具類(lèi)發(fā)送