需求背景
基于微信的通知渠道,微信APP为开发者提供可有效访问用户的模板消息功能,用户自身与微信页面交互后触发,通过微信列表的服务通知快速访问短信
微信小程序允许分发模板消息的条件分为两种:支付或提交表单。 通过提交表单分发模板消息的限制是“允许开发者在7天内向用户推送有限数量的模板消息(一次表单提交可以分发一条,多次提交时条数独立,互不影响)”
但是,用户在单个触发器中在7天内推送一个通知显然是不够的。 例如,登录功能用于通过推送模板消息提醒用户每日登录,只有在前一天登录的情况下才能获得推送模板消息的机会,并在第二天向该用户发送登录通知。 但是,在很多情况下,用户有一天忘记了签名,系统失去了警告用户的权限,与用户的联系被切断。 例如,虽然系统希望主动告知用户已计划事件,但由于微信小程序被动地触发通知的限制,系统不能主动地推送消息。
如何确保模板消息的推送不受限制?
突破口:“一次提交表格一份,多次提交条数独立,互不影响”
为了突破模板消息推送限制,实现7天任性推送,每次提交表格时只需收集足够的推送代码formId。 formId表示开发人员有权向当前用户推送模板消息。
客户端
收集推送代码
如果表单组件的属性report-submit=true,则提交表单时将检索formId并发送模板消息。 然后,改造原始页面,将用户绑定单击事件的界面替换为表单组件的button按钮组件。 也就是说,通过将用户的交互式点击的bindtap事件替换为表单bindsubmit,捕获用户的点击事件并生成更多的推送代码。 //收集推送代码
page({
FORMsubmit:funcition(e ) {
let formId=e.detail.formId;
this.collectformids(formid; //保存推送代码
lettype=e.detail.target.dataset.type; 根据type执行点击事件
(,
CollectFormids3360function{
letformids=app.global data.global formids; //获取全局推送代码数组
if (! formIds )
格式=[ ];
let data={
formId: formId,
expire:newdata(.gettime ) ) 60480000 //7天后过期的时间戳
}
Formids.push(data;
app.global data.global formids=formids;
(,
() )
提升推送代码
等待用户下次启动网络请求,然后将globalFormIds发送到服务器。 //升级推送代码
page({
Onload:funcition(e ) {
this.uploadFormIds (; //上传推送代码
(,
CollectFormids3360function{
varfor mids=app.global data.global formids; //获取全局推送代码
格式. length (if ) {
Formids=JSON.stringify(Formids ); 转换为JSON字符串
app.globalData.gloabalFomIds=' '; //清空当前全局推送代码
}
wx.request(//发送到服务器
url: 'http://xxx ',
方法: ' post ',
数据: {
openId: 'openId ',
格式:格式
(,
success :函数(RES ) {
}
);
(,
() )
服务器端
保存推送代码
使用高频IO、Redis存储推送代码。 //*
*收集用户推送代码
*
* @param openId用户的openid
* @param formTemplates用户的表单模板
*/
公共语音集合(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天内,对用户发送多条模板消息唤回用户。
这就是实现微信小程序模板消息不受限制、无限主动推送的方法详细的所有内容。
相关文章: