文档章节

【小程序】使用模板消息发送消息给多个用户

o
 osc_gu9d45li
发布于 2019/04/30 15:43
字数 1827
阅读 5
收藏 0

精选30+云产品,助力企业轻松上云!>>>

使用模板消息发送消息给多个用户

一、需求背景

  基于微信的通知渠道,微信小程序为开发者提供了可以高效触达用户的模板消息能力,在用户本人与小程序页面有交互行为后触发,通过微信聊天列表中的服务通知可快捷进入查看消息,点击查看详情还能跳转到下发消息的小程序的指定页面。

  微信小程序允许下发模板消息的条件分为两类:支付或者提交表单。通过提交表单来下发模板消息的限制为“允许开发者向用户在7天内推送有限条数的模板消息(1次提交表单可下发1条,多次提交下条数独立,相互不影响)”。

 

  然而,用户1次触发7天内推送1条通知是明显不够用的。比如,签到功能利用模板消息的推送来提醒用户每天签到,只能在用户前一天签到的情况下,获取一次推送模板消息的机会,然后用于第二天向该用户发送签到提醒。但是很多情况下,用户在某一天忘记签到,系统便失去了提醒用户的权限,导致和用户断开了联系;再比如,系统想主动告知用户即将做某活动,然而由于微信小程序被动触发通知的限制,系统将无法主动推送消息。

 

二、如何突破模板消息的推送限制?

  为了突破模板消息的推送限制,实现7天内任性推送,只需收集到足够的推送码,即每次提交表单时获取到的formId。一个formId代表着开发者有向当前用户推送模板消息的一次权限。

 

  

 三、实现

  1.收集推送码。获取多个表单id并保存,便于一次性发送给服务器

  // 收集推送码
  Page({
    formSubmit: funcition(e) {//form表单按钮点击调用该方法
      let formId = e.detail.formId; //获取表单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;
      },
    })

  2.上传推送码。即将推送码发送给服务器然后保存起来(需要上传的数据:formId和openId)

    // 上报推送码
    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',//openId为小程序的用户唯一标识,需自行获取
          formIds: formIds//表单id
        },
        success: function(res) {
          }
        });
      },
    })

  3.服务端-存储推送码(高频IO,采用Redis来存储推送码。将推送码保存到数据库实现持久化存储,由于formId有七天有效期,所以需要定时清理无效推送码)

  

    /**
    * 收集用户推送码
    *
    * @param openId   用户的openid
    * @param formIds  用户的formId
    */
    public void collect(String openId, List<FormTemplateVO> formTemplates) {
      redisTemplate.opsForList().rightPushAll(openId, formIds);
    }

 

  4.发送模板消息相关接口

  相关接口详细信息请查看官方文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/

  需要使用的接口:

  1>模板消息发送api:POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
  要想使用该接口发送模板消息,还需要获取 ACCESS_TOKEN 即接口调用凭证
 

 

 

2>接口调用凭证api:GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
获取接口调用凭证需要appid和secret
appid:小程序唯一标识
secret:小程序唯一凭证密钥
appid和secret获取方式请查看:https://jingyan.baidu.com/article/8cdccae9221703315513cd6e.html

 

5.推送模板消息。发送消息给用户

templateId消息模板id:自行登录https://mp.weixin.qq.com/获取

以下两个方法只是部分代码,调用sendTemplateMessage方法即可发送消息

  /**
  * 发送模板消息
  *
  * @param accessToken 接口调用凭证
  * @param touser 接收者(用户)的 openid
  * @param templateId 所需下发的模板消息的id
  * @param page 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转
  * @param formId 表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id
  * @param data 模板内容,不填则下发空模板。具体格式请参考示例。
  * @param emphasisKeyword 模板需要放大的关键词,不填则默认无放大
  */
  public WxResSendTemplateMessage sendTemplateMessage(String accessToken, String touser, String templateId, String page, String formId, Map<String, Object> data, String       emphasisKeyword) {

    /**
    * data示例:
    *
    * "data": {
    * "keyword1": { "value": title, "color": "#173177" },
    * "keyword2": { "value": gettime() }
    * }
    * emphasisKeyword示例:
    * "emphasis_keyword": "keyword1.DATA"
    *
    */

    /** 结果 */
    String result = "";
    /** 获取输出流 */
    OutputStreamWriter os = null;
    /** 获取输入流 */
    BufferedReader in = null;

    /** 请求地址 */
    String urlPath = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=" + accessToken;

    /** 需要传递的数据 */
    Map<String, Object> messageData = new HashMap<>();
    messageData.put("touser", touser);//接收者(用户)的 openid
    messageData.put("template_id", templateId);//所需下发的模板消息的id
    messageData.put("page", page);//点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转
    messageData.put("form_id", formId);//表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id
    messageData.put("data", data);//模板内容,不填则下发空模板。具体格式请参考示例。
    messageData.put("emphasis_keyword", emphasisKeyword);//模板需要放大的关键词,不填则默认无放大

    try {
      /** 获得url对象 */
      URL url = new URL(urlPath);

      /** 打开连接 */
      HttpURLConnection conn = (HttpURLConnection) url.openConnection();

      /** 设置通用的请求属性 */
      conn.setRequestProperty("accept", "*/*");
      conn.setRequestProperty("connection", "Keep-Alive");
      conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
      conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

      /** 设置请求方式 */
      conn.setRequestMethod(Http.HttpMethod.POST.name());

      /** 设置允许读写出数据,默认可以读不可写 */
      conn.setDoOutput(true);
      conn.setDoInput(true);

      /** 获取输出流 */
      os = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");

      /** 发送请求参数 */
      os.write(JsonMapper.toJsonString(messageData));

      /** 输出缓存流 */
      os.flush();

      /** 获取输入流 */
      in = new BufferedReader(new InputStreamReader(conn.getInputStream()));

      /** 接收行数据 */
      String line;

      /** 读取数据 */
      while((line = in.readLine()) != null) {
        result += line;
      }

    } catch(Exception e) {
      e.printStackTrace();
    } finally {/** 释放输入输出流并关闭 */
    try {
      if(os != null) {
        os.close();
      }
      if(in != null) {
        in.close();
      }
     } catch (Exception e) {
       e.printStackTrace();
     }
    }

    logger.error(">>>模板消息发送>>>result={}>>>", result);

    return (WxResSendTemplateMessage) JsonMapper.fromJsonString(result, WxResSendTemplateMessage.class);
  }

 

    /**
    * 获取小程序全局唯一后台接口调用凭据(access_token)
    *
    * @param appId 小程序唯一凭证
    * @param secret 小程序唯一凭证密钥
    * @return
    * @throws BusinessException
    */
    public WxResAccessToken getAccessToken(String appId, String secret) throws BusinessException {

      String requestUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + secret;

      String res = HttpUtils.get(requestUrl, HttpContentType.CONTENT_TYPE_FORM_DATA, null, null);

      if (StringUtils.isBlank(res)) {
        throw BusinessException.create("获取信息失败!");
      }
      try {
        res = new String(res.getBytes("ISO-8859-1"), "UTF-8");
      } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
      }
      Map<String, Object> map = JsonUtils.unPackMap(res, String.class, Object.class);

      if (map == null) {
        throw BusinessException.create("获取信息失败!");
      }
      if (map.containsKey("errcode")) {
        throw BusinessException.create(String.valueOf(map.get("errmsg")));
      }

      WxResAccessToken out = new WxResAccessToken();
      /** 获取到的凭证 */
      out.setAccessToken(String.valueOf(map.get("access_token")));
      /** 凭证有效时间,单位:秒。目前是7200秒之内的值 */
      if(map.get("expires_in") != null) {
        out.setExpiresIn(BaseUtils.getLong(String.valueOf(map.get("expires_in"))));
      }else {
        out.setExpiresIn(0L);
      }
      /** 错误码 */
      if(map.get("errcode") != null) {
        out.setErrcode(BaseUtils.getLong(String.valueOf(map.get("errcode"))));
      }else {
        out.setErrcode(0L);
      }
      /** 错误信息 */
      out.setErrmsg(String.valueOf(map.get("errmsg")));

      return out;
    }

 

注意:

openid、secret 、appid必须成套

模板消息内容的json字符串需严格按官方给出的格式

 

参考:

https://www.jianshu.com/p/e9641aabb051

https://blog.csdn.net/rolan1993/article/details/79398362

https://blog.csdn.net/xcrow/article/details/37731719

 

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
升级微信订阅消息必知的 5 个细节 | 附实战教程

前言 微信官方为提升小程序模板消息的使用体验,调整了模板消息的下发条件。原有的模板消息将升级为「订阅消息」,而模板消息接口于 2020 年 4 月 10 日下线(在 2020 年 1 月 10 日以后新发...

知晓云
01/13
27
0
使用WePush批量发送模板消息

WePush是什么 WePush是一款专注批量推送的小而美的工具, 目前支持:模板消息-公众号、模板消息-小程序、微信客服消息、阿里云短信、阿里大于模板短信 、腾讯云短信、云片网短信。 可以在Win...

RememBerBe
2018/07/23
307
0
FineReport如何手动推送APP消息

在报表填报成功后,发送消息至APP会提示数据已更新。再次期间用户需要有查看该模板的权限,如果没有的话,则无法接受到提示信息。那么在FineReport移动端中,如何手动推送APP消息呢? 具体用...

雄霸天下啦
2018/06/26
0
0
FineReport如何手动推送APP消息

在报表填报成功后,发送消息至APP会提示数据已更新。再次期间用户需要有查看该模板的权限,如果没有的话,则无法接受到提示信息。那么在FineReport移动端中,如何手动推送APP消息呢? 具体用...

雄霸天下啦
2017/01/19
0
0
微信消息推送

1.微信消息推送测试 微信公众号测试入口 ------->接口网址不好找啊 点击使用手机扫码进入,右键保存测试公众号二维码,如下(后面测试要用) 如果有多个用户扫码关注,则都会在右边显示出来,...

osc_3md1xrlp
2018/08/19
2
0

没有更多内容

加载失败,请刷新页面

加载更多

图解ARP协议(二)ARP***原理与实践

一、ARP***概述 在上篇文章里,我给大家普及了ARP协议的基本原理,包括ARP请求应答、数据包结构以及协议分层标准,今天我们继续讨论大家最感兴趣的话题:ARP***原理是什么?通过ARP***可以做...

osc_91g5cdgs
5分钟前
0
0
shell进度条实现

#!/bin/bashb=''i=0while [ $i -le  100 ]do    printf "progress:[%-50s]%d%%\r" $b $i    sleep 0.1    i=`expr 2 + $i`            b=#$b......

osc_npw5uz1o
6分钟前
8
0
通过ssh实现登录服务器脚本

版本v1 #!/bin/bash########################author: Bovin########################show all host infos of serverList.txtif [[ -f $HOME/.serverList.txt ]]then  hos......

osc_lt2jwwhb
8分钟前
0
0
VMware Fusion下Centos联网

1.VMware Fusion设置选择“网络适配器” 2.“连接我的网络适配器”选择“与我的mac共享” 3.编辑centos的ip配置文件 [root@Centos ~]# more /etc/sysconfig/network-scripts/ifcfg-eth0D...

osc_pg5rp78i
9分钟前
0
0
Kickstart配置文件参数详解

kickstart是什么? KickStart是一种无人值守的安装方法。它的工作原理时在安装过程中记录典型的需要人工干预填写的各种参数,并生成一个名为ks.cfg的文件。如果在安装过程中(不只局限于生成K...

osc_r9yyhhqz
10分钟前
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部