精华内容
下载资源
问答
  • 最近在做微信小程序,为了让用户能更加方便的获取到小程序内部的通知,便想着用模板消息来解决此类问题。首先介绍一下两种方法 第一种是传统的按照微信开发文档来实现模板消息的获取,首先要明确的是你要有一个第三...
  • 基于微信的通知渠道,微信小程序为开发者提供了可以高效触达用户的模板消息能力,在用户本人与小程序页面有交互行为后触发,通过微信聊天列表中的服务通知可快捷进入查看消息,点击查看详情还能跳转到下发消息的...
  • 微信小程序模板消息推送功能实现代码,含前后端程序(PHP后端)
  • 小程序模板消息

    2018-11-06 16:53:21
    封装可了小程序在后台向微信推送消息是的过程,大大降低难度操作,详细操作过程
  • 这个是我自己写的一个小程序模板消息的demo,下载后直接填上参数就能用
  • 主要介绍了基于Taro的微信小程序模板消息-获取formId功能模块封装实践,小程序提供了一种能力-模板消息,基于微信的通知渠道,我们为开发者提供了可以高效触达用户的模板消息能力,以便实现服务的闭环并提供更佳的...
  • 小程序订阅消息 功能介绍 消息能力是小程序能力中的重要组成,我们为开发者提供了订阅消息能力,以便实现服务的闭环和更优的体验。 订阅消息推送位置:服务通知 订阅消息下发条件:用户自主订阅 订阅消息卡片...
  • 微信小程序模板消息使用说明(官方文档):https://mp.weixin.qq.com/debug/wxadoc/dev/api/notice.html 为了防止对模板消息的滥用,带来不好的用户体验,小程序对模板消息推送做了相应的限制。
  • 主要介绍了C#开发之微信小程序发送模板消息功能,需要的朋友可以参考下
  • 微信小程序模板消息demo,这个是微信小程序中有关模板的使用方式介绍
  • 模板消息由于模板选取不同需要传入参数的名称、值、参数个数也不同
  • 本文实例讲述了微信小程序实现发送模板消息功能。分享给大家供大家参考,具体如下: 一、获取access_token access_token是接口调用的凭证,目前有效期为两个小时,需要定时刷新,重复获取将导致上次获取的access_...
  • 参考官方文档和部分资料,总结小程序模板消息推送以及相关注意事项,楼主踩过的坑,特来与大家分享。 一、开发准备: 1.在微信公众平台-小程序的模板中心申请消息模板 二、实现原理: 文档示例:小程序 + ...

    参考官方文档和部分资料,总结小程序模板消息推送以及相关注意事项,楼主踩过的坑,特来与大家分享。

    一、开发准备:

    1.在微信公众平台-小程序的模板中心申请消息模板


     

    二、实现原理:

    文档示例:小程序 + 接口(PHP)

    小程序部分:

    话不多说,先上效果图:

    示例代码:

    <form bindsubmit="formSubmit" report-submit='true' >
      <view class="btn-area"><button formType="submit">Submit</button></view>
    </form>
    formSubmit: function (e) {
      console.log('form发生了submit事件,formId为:', e.detail)
      var that = this;
      wx.request({
        url: 'https://api.XXX.com/sendTemplateMessage.api',
        data: {
          uid: uid,
          formId: e.detail.formId
        },
        method: 'post',
        header: {'content-type': 'application/x-www-form-urlencoded'}, //使用这种方式后台才能实现获取到数据
        success: function (res) {
          console.log("发送模板:" + res.data)
        }
      })

    注意事项:

    小程序通submit点击事件获formid在安卓和IOS是不一样的,安卓系统中为13位时间戳,而IOS系统中为32位字符串,在做接口请求时,不需要做额外处理。

                           安卓系统                                                                        IOS系统

          

     

    PHP接口部分:

    1.根据微信公众平台 --  设置  --  消息推送 -- URL(服务器地址),在PHP项目配置入口文件,实现请求分发。

    2.验证入口文件,传递token令牌(消息推送的token),进行Signature签名有效性验证,完成之后才能进行消息模板的服务器URL地址配置。

    <?php
        define('SS_START_TIME', microtime(true));
        define('RUN_SS', true);
        require '../ss/ss.php';
        $ss = new ss('xcx');
        $ss->execute('xcx', 'valid', 'xcx');
    ?>
    
    <?php
        // 小程序验证入口文件
        public  function xcx(){
            $type = $token;    //Token(令牌)
            if ($this->checkSignature($type) && isset($_GET['echostr'])){
                echo $_GET['echostr'];
                exit();
            }
        }   
    
        /**
         * 校验微信加密签名
         * @return bool
         */
        private function checkSignature($type = ''){
            // 微信服务器配置Token
            $token = $type;
    
            // 1.将timestamp,token,nonce按字典序排序
            $timestamp = $_GET['timestamp'];
            $nonce = $_GET['nonce'];
            $signature = $_GET['signature'];
    
            $arr = array($timestamp, $token, $nonce);
            sort($arr, SORT_STRING);
    
            // 2.拼接为字符串并sha1加密
            $tmpStr = implode($arr);
            $tmpStr = sha1($tmpStr);
    
            // 3.与signature对比判断是否来自微信服务器
            return $tmpStr == $signature ? true:false;
        }     
    ?>

    可在https://mp.weixin.qq.com/debug/调试获取access_token

    3.微信公众平台-设置-开发设置配置消息推送(需要先将入口文件上传服务器)

    4.在微信公众平台获取相关参数:

    AppID(小程序ID)、AppSecret(小程序密钥)、Token(令牌)、TemplateId(模板id)、EncodingAESKey(消息加密密钥)

    4.1  小程序模板接口

        /*
         *小程序模板消息
         *@param uid 用户id
         *$param template_id 模板id
         *@param form_id 表单提交场景下formId(只能用一次)
         *@param emphasis_keyword 消息加密密钥
        */
        public function sendTemplateMessage($uid,$form_id,$template_id){
            // 检验uid合法性 防止非法越界
            $nickname = "nickname";  // 用户昵称
            // 此openid为小程序的openid切勿与微信自动登录的openid混淆
            $xcx_open['openid'] = "用户openid";
            // openid可以通过PHP接口或者小程序获取
            if ($xcx_open['openid']) {
                $temp_msg = array(
                    'touser' => "{$xcx_open['openid']}",
                    'template_id' => "{$template_id}",
                    'page' => "/pages/index/index",
                    'form_id' => "{$form_id}",
                    'data' => array(
                        'keyword1' => array(
                            'value' => "{$nickname}",
                        ),
                        'keyword2' => array(
                            'value' => date('Y-m-d H:i:s', time()),
                        ),
                        'keyword3' => array(
                            'value' => "好友已完成测试,快去看看吧!",
                        ),
                        'keyword4' => array(
                            'value' => "你收到1封新信件,快去看看吧~",
                        ),
                    ),
                    'emphasis_keyword'=> "{$emphasis_keyword}"
                );
                $res = $this->sendXcxTemplateMsg(json_encode($temp_msg));
                echo "<pre>";var_dump($res);exit;
            }
        }

    4.2 发送小程序模板消息

        /**
         * 发送小程序模板消息
         * @param $data
         * @return array
        */
        public function sendXcxTemplateMsg($data,$appid = "",$appsecret = "")
        {
            // 具体模板格式参考公众平台申请的template_id
            if (!$appid || !$appsecret)
            {
                $appid        = '';    //小程序id
                $appsecret    = '';    //小程序秘钥 
            }
            $access_token = $this->getXcxAccessToken($appid,$appsecret);
            $url = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token={$access_token}";
            return $this->http_request($url, $data);
        }

    请求数据格式如下:

    {
      "touser": "OPENID",
      "template_id": "TEMPLATE_ID",
      "page": "index",
      "form_id": "FORMID",
      "data": {
          "keyword1": {
              "value": "339208499"
          },
          "keyword2": {
              "value": "2015年01月05日 12:30"
          },
          "keyword3": {
              "value": "腾讯微信总部"
          } ,
          "keyword4": {
              "value": "广州市海珠区新港中路397号"
          }
      },
      "emphasis_keyword": "keyword1.DATA"
    }

    4.3 获取access_token

        /**
         * 获取微信接口调用凭证
         * @param string $appid
         * @param string $appsecret
         * @return mixed
        */
        public function getXcxAccessToken($appid = '', $appsecret = '')
        {
            if (!$appid || !$appsecret)
            {
                $appid        = '';
                $appsecret    = '';
            }
    
            // 缓存获取
            $cache = &factory::cache();
            if (!$cache->get($appid.'xcx_access_token'))
            {
                $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$appsecret}";
                $res = $this->http_request($url);
                // access_token设置到缓存中
                $cache->set($appid.'xcx_access_token', $res['access_token'], 7000);
                return $res['access_token'];
            }
    
            return $cache->get($appid.'xcx_access_token');
        }

    4.4 CURL模拟HTTP请求(POST)

        /**
         * curl模拟http请求GET/POST
         * @param $url
         * @param null $data
         * @return array
         */
        public function http_request($url, $data = null)
        {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            // 以文件流形式返回
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    
            if (!empty($data))
            {
                // POST请求
                curl_setopt($ch, CURLOPT_POST, 1);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
            }
    
            $output = curl_exec($ch);
            curl_close($ch);
    
            // 返回数组
            return json_decode($output, true);
        }

    传递参数:根据定义接口传递相关参数,用户uid  通过uid获取openid,此openid为小程序的openid, formId 为表单提交场景下,为 submit 事件带上的 formId,formid在安卓和ios下的数据格式和长度不一致,而且小程序获取formid只支持真机调试。

    接口调试:errcode 的合法值

    值	说明
    40037	template_id不正确
    41028	form_id不正确,或者过期
    41029	form_id已被使用
    41030	page不正确
    45009	接口调用超过限额(目前默认每个帐号日调用限额为100万)

    请求成功:

    {
        "state": 1,
        "data": {
            "errcode": 0,
            "errmsg": "ok"
        },
        "info": "successful!"
    }

    至此,推送功能完整实现!

    帮助文档:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/template-message/sendTemplateMessage.html

     

    【PHPer技术栈】专注后端开发,倡导开源文化,做一个好玩、有趣、有灵魂的PHPer工程师,欢迎大家关注!

    展开全文
  • springboot对接小程序登录、模板消息完整代码、springboot对接小程序登录、模板消息完整代码
  • 主要介绍了详解微信小程序开发之formId使用(模板消息),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 原创: 冷思真 蒋鸿昌 首发:「知晓程序」公众号 - 最好的微信新商业媒体 尽管部分运营者还在传授如何运用模板消息召回用户的运营技巧,但对部分开发者而言,模板消息已经...刚刚,微信发布了小程序模板消息能力调...

    原创: 冷思真 蒋鸿昌
    首发:「知晓程序」公众号 - 最好的微信新商业媒体

    在这里插入图片描述

    尽管部分运营者还在传授如何运用模板消息召回用户的运营技巧,但对部分开发者而言,模板消息已经成了食之无味弃之可惜的存在。与其再在模板消息上下功夫,不如好好研究一下如何从「用户分享」和「最近使用」这些更重要的入口召回用户。
    微信当然不会等着模板消息最终成为一个用户心烦、运营者头痛的存在。
    刚刚,微信发布了小程序模板消息能力调整的通知。原先的模板消息接口将停止使用,而新的小程序订阅消息接口也将上线后。从「模板消息」到「订阅消息」,消息变得更加灵活,而用户作为消息接收端的地位则更加主动。

    长期性订阅消息来了,一次性订阅消息打破时间限制

    对于开发者而言,模板消息能力调整中最令人激动的可能就是长期性订阅消息终于来了。用户订阅一次后,开发者则可长期下发多条消息。
    如果你只是小程序的一个普通用户,那你估计也接受过很多并不想要的模板消息推送。当还有限制的模板消息变成长期性,那对用户体验而言可能是个灾难。
    微信也考虑到了这一点,所以长期性订阅消息,目前仅向政务民生、医疗、交通、金融、教育等线下公共服务开放,后期将逐步支持到其他线下公共服务业务。仅就线下公共服务这一点,长期性订阅消息就和大部分开发者无缘了。
    在这里插入图片描述
    图:小程序有了类似 app 的推送能力
    可以预见的是,微信后期对开放长期性订阅消息资格应该会慎之又慎。
    不过对普通开发者而言,长期性订阅消息没戏也能关注一下一次性订阅消息。和之前的模板消息不同,一次性订阅消息没有时间限制,不再受之前的七天时间制约。同时,一次性订阅消息只能发一次,开发者不再能完成多次推送。
    在这次模板消息能力调整中,用户的「订阅」也变得更为清晰。不像之前完成支付、提交表单那样好钻空子。用户在订阅时会收到系统通知,获取用户同意发送特定消息通知。
    开发者可发送怎样的通知更加明晰,每条消息也可单独订阅或退订,对用户而言非常友好。

    小程序模板消息接口将下线

    旧的不去,新的不来。
    既然新的订阅消息来了,那么之前的小程序模板消息接口也完成了历史使命,准备下线了。
    在小程序订阅消息接口上线后,原有的小程序模板消息接口将于 2020 年 1 月 10 日下线,届时开发者将无法使用此接口发送模板消息。

    关于诱导用户订阅的问题,微信也想到了

    模板消息变订阅消息,开发者自然也要思考如何让用户主动订阅消息。
    这其中必然有开发者想用一些运营技巧来促使用户主动订阅,诱导订阅也有像当初的小游戏诱导分享那样影响用户体验的可能性。
    在这方面,微信也做了限制。使用订阅消息能力进行诱导订阅、诱导点击、下发与用户预期不符的内容被视为违规。也就是说,订阅后才能继续下一步操作,订阅后用户可获得奖励这些运营技巧都行不通。
    想要用户主动订阅,还是得看小程序是否能提供用户需要的服务。

    从「模板消息」到「订阅消息」,小程序推送的进阶之路

    每年年初的微信公开课 Pro 版上,张小龙都会介绍微信、小程序的下一步走向,甚至有投资人说看懂小程序的最好途径,就是看张小龙的演讲。
    微信公开课 Pro 版 2019 上,张小龙着重提到希望增强小程序的找回能力。推送是找回小程序的重要途径,但微信的模板消息有两个问题:一是模板消息只能在 7 天内下发,对一些开发者来说限制过大;二是「用户主动确认才能推送」的界限并不清晰,用户经常会被骚扰,微信提供的解决方案是用户可以选择「拒收通知」,但这样就直接切断了用户和小程序间的联系。
    这一次,微信明晰了模板消息的推送逻辑,用户主动订阅的情况下,开发者才能进行消息推送。在「取餐提醒」、「会员积分变动提醒」等一次性模板消息场景下,用户能够清晰地看到自己订阅的功能。
    在这里插入图片描述
    如何和 app 的推送做个类比,微信是将小程序「推送」功能进一步细化到每个需要推送的模块,每个模块都需要用户主动确定,而不是在用户选择接收推送后,一股脑地将服务信息、营销信息推送给用户。
    长期性订阅消息则是更大的亮点,小程序终于有了类似 app 的推送机制。微信对政务民生、医疗、交通、金融、教育等线下公共服务的限定,也在尽力避免对用户造成骚扰。
    微信对这次更新其实早有铺垫。上个月更新的微信 7.0.7 for iOS 增加了小程序权限管理功能,用户可以看到并选择是否允许其发送服务通知。
    在这里插入图片描述
    上月底,微信还在小游戏开发者中内测了新的订阅消息能力,虽然和过去一样是一次性订阅,但微信增加了排名下降提醒、当日排名结算通知、体力恢复提醒、活动开启通知等 14 个模板,只有在用户主动点击游戏内某按钮或元素进行订阅的情况下才能推送模板消息。
    在这里插入图片描述
    腾讯旗下的保险服务平台微保是最先接入内测「长期性订阅消息」的小程序之一,微保 CEO 刘家明告诉知晓程序,相比一次性订阅消息,长期性订阅消息对用户召回的作用要好得多,但在实际推送中,微保也会克制推送的次数,骚扰用户最终导致被拒收通知,会是得不偿失的事情。对于获得长期性订阅消息的开发者来说,这非常值得注意。

    访问「知晓云」(cloud.minapp.com),让你的小程序开发快人一步

    在这里插入图片描述

    展开全文
  • 基于laravel实现模板消息发送(微信小程序版),示例代码已给出,有什么问题可以联系作者,保证帮你调试成功,以前看前人的代码看半天还不如自己写一个。
  • 支付宝小程序模板消息

    千次阅读 2019-10-25 13:59:11
    **formId :**页面的 组件,属性 report-submit 为 true 时,可以声明为需发模板消息,此时用户点击按钮提交表单可以获取 formId,用于发送表单类模板消息。 **tradeNo :**当用户完成支付行为时,可以获取 tradeNo ...

    使用说明

    1、选用模板,获取模板 ID。
    2、通过 form组件 获取 formId 或 tradeNo 属性。
    formId: 页面的 组件,属性 report-submit 为 true 时,可以声明为需发模板消息,此时用户点击按钮提交表单可以获取 formId,用于发送表单类模板消息。
    tradeNo: 当用户完成支付行为时,可以获取 tradeNo 用于发送交易类模板消息。
    3、调用接口下发模板消息。
    下发模板消息的接口名称为:alipay.open.app.mini.templatemessage.send
    4、参考官方文档:模板消息

    消息类型

    交易类: 当用户在小程序内完成支付行为,可允许开发者向付款用户在 7 天内推送有限条数的模板消息(同个订单号只能发送 3 条消息,不限制模板数),当开发者调用交易类的模板消息时,必须要传入 tradeNo 。

    表单类: 当用户在小程序内发生过提交表单行为且该表单为要发模板消息的,可允许开发者向用户在 7 天内推送有限条数的模板消息( 1 次提交表单可下发 3 条,不限制模板数),当开发者调用表单类的模板消息时,必须要传入 formid 。

    时效性: 开发者获取 formId 或 tradeNo 后,可在 7 天内向用户推送消息,超出后 formId 或 tradeNo 将失效,无法推送消息。

    调用接口下发模板消息

    引入maven

     <!-- 支付宝 -->
      <dependency>
          <groupId>com.alipay.sdk</groupId>
          <artifactId>alipay-sdk-java</artifactId>
          <version>4.7.11.ALL</version>
      </dependency>
      <dependency>
          <groupId>com.alipay</groupId>
          <artifactId>sdk-java</artifactId>
          <version>20170612154830</version>
      </dependency>
    
      <!-- hutool -->
      <dependency>
          <groupId>cn.hutool</groupId>
          <artifactId>hutool-all</artifactId>
          <version>5.0.2</version>
      </dependency>
    
      <!-- lombok -->
      <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>1.16.10</version>
      </dependency>
    
      <!-- fastjson -->
      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
          <version>1.2.48</version>
      </dependency>
    
      <!-- lang -->
      <dependency>
          <groupId>commons-lang</groupId>
          <artifactId>commons-lang</artifactId>
          <version>2.6</version>
      </dependency>
    

    配置application.properties

    #小程序
    alipay.push.message.template.appid=你的小程序appId
    #开发者私钥,由开发者自己生成
    alipay.push.message.template.privateKey=开发者私钥
    #支付宝公钥,由支付宝生成
    alipay.push.message.template.alipayPublicKey=支付宝公钥
    #模板Id
    alipay.push.message.template.id=你的模板Id
    #支付宝网关(固定)
    alipay.push.message.template.serverUrl=https://openapi.alipay.com/gateway.do
    #商户生成签名字符串所使用的签名算法类型,目前仅支持 RSA2
    alipay.push.message.template.signType=RSA2
    

    模板消息实体类

    @Data
    public class AlipayTemplateParam {
        /**
         * 小程序app_id
         */
        private String appId;
    
        /**
         * 私钥
         */
        private String privateKey;
    
        /**
         * 公钥
         */
        private String alipayPublicKey;
    
        /**
         * 要发送消息的用户
         */
        private String to_user_id;
    
        /**
         * from_id
         */
        private String form_id;
    
        /**
         * 模板Id
         */
        private String user_template_id;
    
        /**
         * 点击消息通知卡片跳转的页面
         */
        private String page;
    
        /**
         * 需要发送模板消息中自定义部分 {{keyworld1.value}}
         */
        private String data;
    }
    

    配置类SysConfig

    @Data
    @Configuration
    public class SysConfig {
        /******************支付宝直连参数配置*********************/
        @Value("${alipay.push.message.template.appid}")
        private String appId;
    
        @Value("${alipay.push.message.template.privateKey}")
        private String privateKey;
    
        @Value("${alipay.push.message.template.alipayPublicKey}")
        private String alipayPublicKey;
    
        @Value("${alipay.push.message.template.id}")
        private String templateId;
    
        @Value("${alipay.push.message.template.serverUrl}")
        private String serverUrl;
    
        @Value("${alipay.push.message.template.signType}")
        private String signType;
    }
    

    模板消息推送完整实现类

    @Component
    public class AlipaySendTemplateServiceImpl implements AlipaySendTemplateService {
    
        Logger logger = LoggerFactory.getLogger(AlipaySendTemplateServiceImpl.class);
    
        @Autowired
        private SysConfig sysConfig;
    
        @Override
        public void sendTemplateMessage(PaymentParam param) {
            String appId = sysConfig.getAppId();
            String privateKey = sysConfig.getPrivateKey();
            String publicKey = sysConfig.getAlipayPublicKey();
    
            AlipayTemplateParam templateParam = new AlipayTemplateParam();
            templateParam.setTo_user_id(param.getUserId());
            templateParam.setForm_id(param.getFormId());
            templateParam.setUser_template_id(sysConfig.getTemplateId());
            templateParam.setPage(param.getPage());
            templateParam.setData(getTemplateDataJSON(param));
    
            String paramJson = JSON.toJSONString(templateParam);
    
            AlipayOpenAppMiniTemplatemessageSendRequest request = new AlipayOpenAppMiniTemplatemessageSendRequest();
            request.setBizContent(paramJson);
            logger.info("调用支付宝发送模版消息接口,request = {}",JSON.toJSONString(request));
    
            AlipayOpenAppMiniTemplatemessageSendResponse response = null;
            try{
                response = getAlipayClient(request,appId,privateKey,publicKey);
                if(response != null && response.isSuccess()){
                    logger.info("支付宝发送模版消息成功:response={}", JSON.toJSONString(response));
                }else{
                    logger.info("支付宝发送模版消息异常:errorCode:{}, errorMsg:{}", response.getCode(), response.getSubMsg());
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    
        /**
         * 在 SDK 调用前需要进行初始化,获取lipayClient 只需要初始化一次,后续调用不同的 API 都可以使用同一个 alipayClient 对象
         *
         * @param request
         * @param appId
         * @param privateKey
         * @param alipayPublicKey
         * @param <T>
         * @return
         * @throws AlipayApiException
         */
        private <T extends AlipayResponse> T getAlipayClient(AlipayRequest<T> request, String appId, String privateKey, String alipayPublicKey) throws AlipayApiException {
            String serverUrl = sysConfig.getServerUrl();
            String signType = sysConfig.getSignType();
            AlipayClient alipayClient = new DefaultAlipayClient(serverUrl, appId, privateKey, "json", "utf-8", alipayPublicKey, signType);
            return alipayClient.execute(request);
        }
    
        /**
         * 构建消息体
         *
         * @param param
         * @return
         */
        private String getTemplateDataJSON(PaymentParam param) {
            Map<String, TemplateSendData> dataMap = new HashMap<>();
            String keyword1 = param.getStoreName();
            String keyword2 = param.getTakeOrderNo();
            String keyword3 = param.getReminder();
            String keyword4 = param.getKeyworld4();
            String keyword5 = param.getKeyworld5();
    
            if (StringUtils.isNotBlank(keyword1)) {
                dataMap.put("keyword1", new TemplateSendData(keyword1));
            }
            if (StringUtils.isNotBlank(keyword1)) {
                dataMap.put("keyword2", new TemplateSendData(keyword2));
            }
            if (StringUtils.isNotBlank(keyword1)) {
                dataMap.put("keyword3", new TemplateSendData(keyword3));
            }
            if (StringUtils.isNotBlank(keyword1)) {
                dataMap.put("keyword4", new TemplateSendData(keyword4));
            }
            if (StringUtils.isNotBlank(keyword1)) {
                dataMap.put("keyword5", new TemplateSendData(keyword5));
            }
    
            String dataJson = JSON.toJSONString(dataMap);
            return dataJson;
        }
    }
    
    展开全文
  • go语言发送微信小程序模板消息

    千次阅读 2018-12-31 16:33:28
    为了发一条模板消息翻了无数个博客,很多都是把代码一放,其实代码这块很好弄,不就组装个数据调一下API吗,主要是前期工作。我把我遇到的坑给大家总结一下,希望后来人可以少走一些弯路。 微信发送模板消息文档:...

    PS:开发微信的东西是真的心累,一大堆坑!文档写的乱七八糟的,找个东西都得半天。

    为了发一条模板消息翻了无数个博客,很多都是把代码一放,其实代码这块很好弄,不就组装个数据调一下API吗,主要是前期工作。我把我遇到的坑给大家总结一下,希望后来人可以少走一些弯路。

    微信发送模板消息文档:点击查看

    1. 超级大坑!发送接口问题

    文档上是这个接口:

    https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
    

    实际不是的!!!!!是下面这个,看见没,多了一个wxopen,如果你碰到 48001 返回码,看看是不是这出问题了。

    https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
    
    1. 域名问题

    他们这个必须要配置合法域名,必须是https的,要有SSL证书的,在微信开发工具上可以看到你目前配置的合法域名

    1. 内网穿透问题

    因为formID必须要在真机上才可以获取,所以你最好设置一个内网穿透,让手机能访问到你本地的服务。

    内网穿透工具可以去下面网站上下载,有免费的
    https://www.ngrok.cc

    1. 证书问题
      在腾讯云上下载的证书是下面这个样子的:

    这时你在go语言就不知道用哪个里面的证书了。。。我用的gofram框架,可以这样搞,
    将Apache里面的

    这两个东西,通过下面网站生成一个 .pem证书然后再用到go语言中就好使了。
    https://www.myssl.cn/tools/merge-pem-cert.html
    go语言中这样用

    s.EnableHTTPS("https/ssl.pem", "https/3_pibigstar.com.key")
    s.SetHTTPSPort(7777)
    

    还有一个坑就是,端口不能是443,可能是我本机是Windows,把443端口屏蔽了,如果你一直出现404情况,换个端口!

    大概就些坑,如果你碰到其他的坑可以给我留言,或关注我的微信公众号,希望可以帮到你。

    放代码

    go后端

    import (
    	"bytes"
    	"encoding/json"
    	"fmt"
    	"io/ioutil"
    	"net/http"
    	"time"
    
    	"github.com/pibigstar/go-todo/config"
    	"github.com/pibigstar/go-todo/constant"
    	"github.com/pibigstar/go-todo/models/db"
    )
    
    // 发送模板消息
    
    var (
    	send_template_url    = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=%s"
    	get_access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"
    )
    
    // SendTemplate 发送模板消息
    func SendTemplate(msg *TemplateMsg) (*SendTemplateResponse, error) {
    	msg.Miniprogram.AppID = config.ServerConfig.Appid
    	accessToken, err := getAccessToken(msg.Touser)
    	if err != nil {
    		log.Error("获取accessToken失败")
    		return nil, err
    	}
    	url := fmt.Sprintf(send_template_url, accessToken.AccessToken)
    	data, err := json.Marshal(msg)
    	if err != nil {
    		log.Error("模板消息JSON格式错误", "err", err.Error())
    		return nil, err
    	}
    	client := http.Client{}
    	resp, err := client.Post(url, "application/json", bytes.NewBuffer(data))
    	if err != nil {
    		log.Error("网络错误,发送模板消息失败", "err", err.Error())
    		return nil, err
    	}
    	defer resp.Body.Close()
    	body, _ := ioutil.ReadAll(resp.Body)
    	var templateResponse SendTemplateResponse
    	err = json.Unmarshal(body, &templateResponse)
    	if err != nil {
    		log.Error("解析responseBody错误", "err", err.Error())
    		return nil, err
    	}
    	return &templateResponse, nil
    }
    
    func getAccessToken(openID string) (*GetAccessTokenResponse, error) {
    	var accessTokenResponse GetAccessTokenResponse
    	// 先从redis中拿
    	accessToken, err := getAccessTokenFromRedis(openID)
    	if accessToken != "" && err == nil {
    		accessTokenResponse = GetAccessTokenResponse{AccessToken: accessToken}
    		log.Info("从redis中获取到access_token", "access_token", accessToken)
    		return &accessTokenResponse, nil
    	}
    	appID := config.ServerConfig.Appid
    	secret := config.ServerConfig.Secret
    	url := fmt.Sprintf(get_access_token_url, appID, secret)
    	client := http.Client{}
    	resp, err := client.Get(url)
    	if err != nil {
    		log.Error("获取access_toke网络异常", "err", err.Error())
    		return nil, err
    	}
    	defer resp.Body.Close()
    	body, _ := ioutil.ReadAll(resp.Body)
    	err = json.Unmarshal(body, &accessTokenResponse)
    	if err != nil {
    		log.Error("解析AccessToken失败", "err", err.Error())
    		return nil, err
    	}
    	// 存到redis中
    	if _, err := setAccessTokenToRedis(openID, accessTokenResponse.AccessToken); err != nil {
    		log.Error("将access_token存储到redis中失败", "err", err.Error())
    	}
    	return &accessTokenResponse, nil
    }
    
    // 从redis中取access_token
    func getAccessTokenFromRedis(openID string) (string, error) {
    	key := fmt.Sprintf(constant.Access_Token_Redis_Prefix, openID)
    	accessToken, err := db.Redis.Get(key).Result()
    	return accessToken, err
    }
    
    // 将access_token存储到redis中
    func setAccessTokenToRedis(openID, token string) (string, error) {
    	key := fmt.Sprintf(constant.Access_Token_Redis_Prefix, openID)
    	b, err := db.Redis.Set(key, token, 7200*time.Second).Result()
    	return b, err
    }
    
    type TemplateMsg struct {
    	Touser      string        `json:"touser"`      //接收者的OpenID
    	TemplateID  string        `json:"template_id"` //模板消息ID
    	FormID      string        `json:"form_id"`
    	URL         string        `json:"url"`         //点击后跳转链接
    	Miniprogram Miniprogram   `json:"miniprogram"` //点击跳转小程序
    	Data        *TemplateData `json:"data"`
    }
    type Miniprogram struct {
    	AppID    string `json:"appid"`
    	Pagepath string `json:"pagepath"`
    }
    
    type TemplateData struct {
    	First    KeyWordData `json:"first,omitempty"`
    	Keyword1 KeyWordData `json:"keyword1,omitempty"`
    	Keyword2 KeyWordData `json:"keyword2,omitempty"`
    	Keyword3 KeyWordData `json:"keyword3,omitempty"`
    	Keyword4 KeyWordData `json:"keyword4,omitempty"`
    	Keyword5 KeyWordData `json:"keyword5,omitempty"`
    }
    
    type KeyWordData struct {
    	Value string `json:"value"`
    	Color string `json:"color,omitempty"`
    }
    
    type SendTemplateResponse struct {
    	Errcode int    `json:"errcode"`
    	Errmsg  string `json:"errmsg"`
    	MsgID   string `json:"msgid"`
    }
    
    type GetAccessTokenResponse struct {
    	AccessToken string `json:"access_token"`
    	ExpiresIn   int    `json:"expires_in"`
    }
    

    controller例子

    仅仅是个例子,供大家参考

    func init() {
    	s := g.Server()
    	s.BindHandler("/send", sendTemplate)
    }
    
    func sendTemplate(r *ghttp.Request) {
    	templateMsg := &utils.TemplateMsg{}
    	tempData := &utils.TemplateData{}
    	tempData.First.Value = "测试模板消息"
    	tempData.Keyword1.Value = "大家记得买票啊"
    	tempData.Keyword2.Value = "马上就要放假了,大家记得买回家的票啊"
    	tempData.Keyword3.Value = "2018-12-30 15:59"
    	tempData.Keyword4.Value = "派大星"
    	tempData.Keyword5.Value = "记得按时完成"
    	templateMsg.Data = tempData
    	formID := r.GetString("formID")
    	log.Info("formID", "formID", formID)
    	templateMsg.FormID = formID
    	openID, _ := middleware.GetOpenID(r)
    	templateMsg.Touser = openID
    	templateMsg.TemplateID = constant.Tmeplate_Receive_Task_ID
    	response, err := utils.SendTemplate(templateMsg)
    	if err != nil {
    		fmt.Println("发送模板消息失败", err.Error())
    	}
    	r.Response.WriteJson(response)
    }
    

    小程序端

    <view>
     <form bindsubmit="templateSend" report-submit="true">
          <button type='primary' formType="submit" size='mini'>发送模板消息</button>
        </form>
    </view>
    
      templateSend: function (e) {
        // 表单需设置report-submit="true"
        var formId = e.detail.formId;
        // 发送随机模板消息
        util.apiRequest("send","get",{
          formID: formId,
          }).then(data => {
             console.log(data)
          })
      }
    
    展开全文
  • 小程序地图导航,显示天气源码 https://github.com/zzwwjjdj319/miniProgramAmap 信微小猜拳游戏程序源码小https://gitee.com/sccqcd/wechat_applet_weather_map ...   最近在做小程序模板消息发...
  • 前不久小程序突然公共说模板消息要改版了,具体内容可以看这 https://developers.weixin.qq.com/community/develop/doc/00008a8a7d8310b6bf4975b635a401?blockType=1 反正大概意思就是模板消息要停用了,会出一个...
  • 模板消息是什么?它是微信为小程序提供...不过,为了防止小程序滥用推送能力去骚扰用户,微信对小程序模板消息作出了许多限制。具体有哪些限制呢?这些限制是否可以在适当的情况下,被「绕过」呢?店老板商户服务(...
  • 小打卡小程序的近30天访问来源数据显示,有20%左右的用户通过模板消息这个入口进入小打卡,在各种来源中排名第三位,可见模板消息是用户使用小程序的重要入口。 模版消息推送是微信小程序采用的通知形式,用户...
  • 加入 \r\n 即可 效果如下
  • 而模块消息将于2020年1月10日下线,小程序将无法再使用原接口推送模板消息,因此开发者需要及时进行调整。 以往,模块消息作为服务进度提醒和召回用户的重要入口,受到了不少小程序运营者的青睐。但是,部分小程序...
  • 小程序模板消息报47001错误

    千次阅读 2018-01-30 13:52:50
    小程序内部调用POST请求发送模板消息,报错误如下: { "errcode":47001, "errmsg":"data format error" } 在这里我的所有请求参数都是正确的,调用的代码如下: function post(url, data, success, ...
  • 但是为了避免这种通知被滥用,带来不好的用户体验,小程序也对模板消息推送做了相应的限制。为了更好的优化小打卡小程序的打卡通知功能,我在开发的过程中自行摸索了一套突破推送限制的解决方案。可以实现7天内向...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 383,889
精华内容 153,555
关键字:

小程序模板消息