示例代码可实现对微信小程序模板消息的限制的无限主动推送
优采云 发布时间: 2020-08-07 23:41示例代码可实现对微信小程序模板消息的限制的无限主动推送
更新时间: 2019年8月27日11:39:44转载作者: Bliss t
本文主要介绍微信小程序模板消息限制实现无限主动推送的示例代码. 本文介绍的示例代码非常详细,对于每个人的学习或工作都有一定的参考学习价值,有需要的朋友让我们与编辑一起学习.
需求背景
基于微信的通知渠道,微信小程序为开发人员提供了模板消息功能,可以有效地到达用户. 在用户与applet页面进行交互之后将触发该事件,并且可以通过微信聊天列表中的服务通知迅速通知该消息. 输入以查看消息,然后单击以查看详细信息以跳至发出消息的小程序的指定页面.
微信小程序允许发送模板消息的条件分为两类: 付款或表单提交. 通过提交表单发送模板消息的限制是“允许开发人员在7天内向用户推送有限数量的模板消息(提交表单后可以发送1个表单,并且多次提交的数量是独立的,并且确实不会互相影响)”.
但是,对于用户而言,仅在一次触发后7天内推送1条通知显然是不够的. 例如,签入功能使用模板消息推送来提醒用户每天签入. 仅当用户在前一天签到时,才有机会推送一次模板消息,然后使用它向第二天向用户发送签到提醒. 然而,在许多情况下,用户忘记了在某一天登录,并且系统失去了提醒用户的权利,从而导致与用户断开连接. 另一个示例,系统希望主动通知用户有关活动的信息,但微信小程序被动触发该通知,系统将无法主动推送消息.
如何突破模板消息的推送限制?
突破: “一次提交一份表格即可,一次提交的次数是独立的,不会互相影响”
为了突破模板消息的推送限制并在7天内实现任意推送,只需采集足够的推送代码,即每次提交表单时获取的formId. formId表示开发人员具有一次将模板消息推送给当前用户的权限.
客户
采集推送代码
当表单组件中的属性report-submit = true时,表示已发送模板消息,并且可以通过提交表单来获取formId. 接下来,只要修改了原创页面,绑定到click事件的用户原创界面就会被表单组件中的button button组件替换,即,用户交互式单击的bindtap事件将被替换为bindsubmit表单. 捕获用户的Click事件以生成更多的推送代码.
// 收集推送码
Page({
formSubmit: funcition(e) {
let formId = e.detail.formId;
this.collectFormIds(formId); //保存推送码
let type = e.detail.target.dataset.type; // 根据type执行点击事件
},
collectFormIds: function(formId) {
let formIds = app.globalData.globalFormIds; // 获取全局推送码数组
if (!formIds)
formIds = [];
let data = {
formId: formId,
expire: new Data().getTime() + 60480000 // 7天后的过期时间戳
}
formIds.push(data);
app.globalData.globalFormIds = formIds;
},
})
报告推送代码
下次用户发起网络请求,并将globalFormId发送到服务器时.
// 上报推送码
Page({
onLoad: funcition(e) {
this.uploadFormIds(); //上传推送码
},
collectFormIds: function(formId) {
var formIds = app.globalData.globalFormIds; // 获取全局推送码
if (formIds.length) {
formIds = JSON.stringify(formIds); // 转换成JSON字符串
app.globalData.gloabalFomIds = ''; // 清空当前全局推送码
}
wx.request({ // 发送到服务器
url: 'http://xxx',
method: 'POST',
data: {
openId: 'openId',
formIds: formIds
},
success: function(res) {
}
});
},
})
服务器端
存储推送代码
高频IO,使用Redis存储推送代码.
/**
* 收集用户推送码
*
* @param openId 用户的openid
* @param formTemplates 用户的表单模板
*/
public void collect(String openId, List formTemplates) {
redisTemplate.opsForList().rightPushAll("mina:openid:" + openId, formTemplates);
}
推送模板消息
群组发送功能在下面实现,类似于特定用户.
/**
* 推送消息
*
* @param templateId 模板消息id
* @param page 跳转页面
* @param keyWords 模板内容
*/
public void push(String templateId, String page, String keyWords) {
String logPrefix = "推送消息";
// 获取access token
String accessToken = this.getAccessToken();
// 创建消息通用模板
MsgTemplateVO msgTemplateVO = MsgTemplateVO.builder().template_id(templateId).build();
// 跳转页面
msgTemplateVO.setPage(StringUtils.isNotBlank(page) ? page : "");
// 模板内容
if (StringUtils.isNotBlank(keyWords)) {
String[] keyWordArr = keyWords.split(BaseConsts.COMMA_STR);
Map keyWordMap = new HashMap(8);
for (int i = 0; i < keyWordArr.length; i++) {
MsgTemplateVO.KeyWord keyWord = msgTemplateVO.new KeyWord(keyWordArr[i]);
keyWordMap.put(MsgTemplateVO.KEYWORD + (i + 1), keyWord);
}
msgTemplateVO.setData(keyWordMap);
} else {
msgTemplateVO.setData(Collections.emptyMap());
}
// 获取所有用户
List openIdList = minaRedisDao.getAllOpenIds();
for (String openId : openIdList) {
// 获取有效推送码
String formId = minaRedisDao.getValidFormId(openId);
if (StringUtils.isBlank(formId)) {
LOGGER.error("{}>>>openId={}>>>已无有效推送码[失败]", logPrefix, openId);
continue;
}
// 指派消息
MsgTemplateVO assignMsgTemplateVO = msgTemplateVO.assign(openId, formId);
// 发送消息
Map resultMap;
try {
String jsonBody = JsonUtils.getObjectMapper().writeValueAsString(assignMsgTemplateVO);
String resultBody = OkHttpUtils.getInstance().postAsString(messageUrl + accessToken, jsonBody);
resultMap = JsonUtils.getObjectMapper().readValue(resultBody, Map.class);
} catch (IOException e) {
LOGGER.error("{}>>>openId={}>>>{}[失败]", logPrefix, openId, e.getMessage(), e);
continue;
}
if ((int) resultMap.get(ResponseConsts.Mina.CODE) != 0) {
LOGGER.error("{}>>>openId={}>>>{}[失败]", logPrefix, openId, resultMap.get(ResponseConsts.Mina.MSG));
continue;
}
LOGGER.info("{}>>>openId={}>>>[成功]", logPrefix, openId);
}
}
/**
* 根据用户获取有效的推送码
*
* @param openId 用户的openid
* @return 推送码
*/
public String getValidFormId(String openId) {
List formTemplates = redisTemplate.opsForList().range("mina:openid:" + openId, 0, -1);
String validFormId = "";
int trimStart = 0;
int size;
for (int i = 0; i < (size = formTemplates.size()); i++) {
if (formTemplates.get(i).getExpire() > System.currentTimeMillis()) {
validFormId = formTemplates.get(i).getFormId();
trimStart = i + 1;
break;
}
}
// 移除本次使用的和已过期的
redisTemplate.opsForList().trim(KEY_MINA_PUSH + openId, trimStart == 0 ? size : trimStart, -1);
return validFormId;
}
上述方案可以在用户最后一次使用该迷你程序后的7天内向用户发送多个模板消息,以召回该用户.