董建军 發表於 2019-8-27 09:23:00

.NET Core 小程序开发零基础系列(2)——小程序服务通知(模板消息)

<p>基于上一篇文件“.NET Core 小程序开发零基础系列(1)——开发者启用并校验牵手成功”的反映,个人觉得效果很不错,大家对公众号开发还是有很大需求的,同时也收到了很多同学的问题,后面我也会通过实战性文章慢慢的表现出来 ,让大家更容易吃得透一些。在这里特别感谢盛派Senparc作者的支持,也感谢各社区大佬的支持,同时也要感谢我的6位小伙伴大力支持,我们将有问必答,资源共享。</p>
<p>&nbsp;</p>
<p>为什么说盛派Senparc开源框架开发贼快呢,因为他们经过多年的打磨,反反复复的修改升级,基本上所有公众号的功能都支持,但发现还是有很多的同学不明白原理与底层框架的设计,在这里我们将通过真实的实战项目来一点点吃掉。</p>
<p>&nbsp;</p>
<p>废话不多说了,开始我们的实战第二篇,玩得好 模板消息可突破限制哦,袖子撸起来,干 ^_^</p>
<p>&nbsp;</p>
<p><strong>了解一下模板消息</strong></p>
<hr>
<p>&nbsp;基于微信的通知渠道,我们为开发者提供了可以高效触达用户的模板消息能力,以便实现服务的闭环并提供更佳的体验。</p>
<p>&nbsp;</p>
<p><strong>模板推送位置:</strong>服务通知</p>
<p><strong>模板下发条件:</strong>用户本人在微信体系内与页面有交互行为后触发,详见&nbsp;<span style="color: rgba(255, 0, 255, 1)">下发条件说明&nbsp;</span></p>
<p><strong>模板跳转能力:</strong>点击查看详情仅能跳转下发模板的该帐号的各个页面</p>
<p>&nbsp;</p>
<p><img src="https://img2018.cnblogs.com/blog/679720/201908/679720-20190826223423195-1385249288.png" alt=""></p>
<p><strong>效果如图:</strong></p>
<p><img src="https://img2018.cnblogs.com/blog/679720/201908/679720-20190826223456162-2044050292.png" alt=""></p>
<p>&nbsp;</p>
<p>更多的规则请查看官方文档</p>
<p>https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/template-message.html</p>
<p>&nbsp;</p>
<p><strong>附加经验说明:</strong></p>
<p>如果你公司有运营人员,一定会非常的喜欢服务通知,它能很快的引流到服务号,小程序中来,激活当前的用户。借助微信的服务通知,必能触达到关注过,授权过服务号,小程序的人,是不是很棒。</p>
<p>&nbsp;</p>
<p>场景:比如说用户使用某个小程序发布了一个百人报名活动。如果能实现有一个人报名,就向活动发起者发送一条报名通知,那就大大提高了工具的使用效率,不用发起人每次都打开小程序去看有多少人参与了报名。显然,当前的消息发送机制无法满足这个需求。</p>
<p>&nbsp;</p>
<p>模板有很多种咯,每个行业的模板也不一样,比如我们电商系统需要的模板“订单支付成功通知”、“订单支付失败通知”、“预约成功通知”、“订单发货通知”、“用户认证通知”等等模板。</p>
<p>&nbsp;</p>
<p><strong>创建你想要的模板/设置模板</strong></p>
<hr>
<p>&nbsp;登录小程序后台,点击左侧“模板消息”,如图:</p>
<p><img src="https://img2018.cnblogs.com/blog/679720/201908/679720-20190826223556162-781056038.png" alt="" width="888" height="348"></p>
<p>&nbsp;</p>
<p>默认“我的模板库”是没有模板的,需要进入到“模板库”中进行创建, 模板库中的模板非常多,建议搜索你想要的模板,如图:</p>
<p><img src="https://img2018.cnblogs.com/blog/679720/201908/679720-20190826223621313-447373053.png" alt="" width="988" height="469"></p>
<p>&nbsp;</p>
<p>选择对应的模板,点击选用,如图:</p>
<p><img src="https://img2018.cnblogs.com/blog/679720/201908/679720-20190826223857889-1427322884.png" alt=""></p>
<p><span style="color: rgba(255, 0, 255, 1)">注意:这里添加的“关键词”顺序要严格按照我们后台列出来的顺序去选择排列,否则会出现数据错乱的问题。</span></p>
<p><span style="color: rgba(255, 0, 255, 1)">以上基本是了解模板,配置模板,下面我们真正来发送模板啦!</span></p>
<p>&nbsp;</p>
<p><strong>收集formId(突破模板消息的推送限制?)</strong></p>
<hr>
<p>&nbsp;</p>
<p>这里为什么要收集formId呢,因为小程序发送模板必须要对应人的formId来发送,不然你是发送不成功的。</p>
<p>&nbsp;</p>
<p>formId收集方法,我们直接讲复杂的收集,突破模板消息的推送限制。</p>
<p>&nbsp;</p>
<p><strong>流程</strong></p>
<p>结合小程序前端界面实现批量收集formId==》上报后台==》存储formId==》发送模板,最终做到7日内推送模板消息、触及用户激活用户。</p>
<p>&nbsp;</p>
<p><strong>实现步骤</strong></p>
<p>1、小程序构建formId 池,每次将用户提交的表单都搜集起来存入formId池,当用户操作前端某个位置或者离开挂起小程序时,发送formIds到后端存储起来。</p>
<p>&nbsp;</p>
<p>2、将小程序用户有可能点击的区域覆盖一层不可见的button,并将整个页面用于传输formId的button包裹在一form标签内,一旦用户有点击按钮的操作,就将获取到的formId存入formId 池。</p>
<p>&nbsp;</p>
<p><strong>上小程序部分代码</strong></p>
<p>1、先定义一个formId数组</p>
<p><img src="https://img2018.cnblogs.com/blog/679720/201908/679720-20190826224017878-645736613.png" alt=""></p>
<p>&nbsp;</p>
<p>2、小程序页面定义事件</p>
<p><img src="https://img2018.cnblogs.com/blog/679720/201908/679720-20190826224022917-1276346349.png" alt=""></p>
<p>&nbsp;</p>
<p>3、提交事件</p>
<p><img src="https://img2018.cnblogs.com/blog/679720/201908/679720-20190826224047910-1301002118.png" alt=""></p>
<p>&nbsp;</p>
<p>4、提交到后台,批量收集formId</p>
<p><img src="https://img2018.cnblogs.com/blog/679720/201908/679720-20190826224111219-2064979761.png" alt=""></p>
<p>&nbsp;</p>
<p><span style="color: rgba(255, 0, 255, 1)">以上基本是收集formId的流程,有不懂原理与实现步骤的可以联系我。</span></p>
<p>&nbsp;</p>
<p><strong>发送模板消息(服务通知)</strong></p>
<hr>
<p>&nbsp;还是上一篇那个项目,如图:</p>
<p><img src="https://img2018.cnblogs.com/blog/679720/201908/679720-20190826224139697-55353172.png" alt=""></p>
<p>&nbsp;</p>
<p>引用盛派Senparc组件:</p>
<p><span style="color: rgba(255, 0, 255, 1)">Senparc.Weixin.MP.MVC</span></p>
<p><span style="color: rgba(255, 0, 255, 1)">Senparc.Weixin.WxOpen</span></p>
<p>&nbsp;</p>
<p>批量发送模板主要代码:</p>
<div class="cnblogs_code">
<pre>HashEntry[] hashes =<span style="color: rgba(0, 0, 0, 1)"> redisManager2.HashValueAll(videoKey);
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (hashes.Length &gt; <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
                {
                  Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{QUEUE_ROOMVISIRECORD},直播间{videoKey},准备推送人数{hashes.Length},videoKey={videoKey},videoKeywords={videoKeywords}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
                  </span><span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> item <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> hashes)
                  {
                         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">{"WorkQueueNo":"wxccf5524125d67d16","TemplateID":"KgI11LMjGCUmvrfOPG5xHdfW2j70tJKNurfrtAFn9sk","Keywords":"2019-08-25 21:54:00|安|fffd|快来我的直播间,约起!","Url":"pages/live/liveRoom/liveRoom?id=1164536425702625280","ToOpenID":"o5D-a5QpNoC_0QYF5C-zFbmkgr4Q","ToMemberID":1053}</span>
                        WorkQueueParam valueItem =DMS.Common.Extensions.SerializerExtensions.DeserializeObject&lt;WorkQueueParam&gt;<span style="color: rgba(0, 0, 0, 1)">(item.Value);
                        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (valueItem != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
                        {
                            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">查找小程序的fromid</span>
                            <span style="color: rgba(0, 0, 255, 1)">string</span> key =$<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{valueItem.ToMemberID}_{valueItem.WorkQueueNo}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
                            </span><span style="color: rgba(0, 0, 255, 1)">string</span> fromid = redisManager3.ListLeftPop&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;<span style="color: rgba(0, 0, 0, 1)">(key);
                            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.IsNullOrEmpty(fromid))
                            {
                              </span><span style="color: rgba(0, 0, 255, 1)">string</span>[] keywords = videoKeywords.Split(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">|</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
                              </span><span style="color: rgba(0, 0, 255, 1)">var</span> data = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)">
                              {
                                    keyword1 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> TemplateDataItem(keywords[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">]),
                                    keyword2 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> TemplateDataItem(keywords[<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">]),
                                    keyword3 </span>= keywords.Length &gt; <span style="color: rgba(128, 0, 128, 1)">2</span> ? <span style="color: rgba(0, 0, 255, 1)">new</span>TemplateDataItem(keywords[<span style="color: rgba(128, 0, 128, 1)">2</span>]) : <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">,
                                    keyword4 </span>= keywords.Length &gt; <span style="color: rgba(128, 0, 128, 1)">3</span> ? <span style="color: rgba(0, 0, 255, 1)">new</span>TemplateDataItem(keywords[<span style="color: rgba(128, 0, 128, 1)">3</span>]) : <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">,
                              };
                              </span><span style="color: rgba(0, 0, 255, 1)">var</span> tempResult =<span style="color: rgba(0, 0, 0, 1)">Senparc.Weixin.WxOpen.AdvancedAPIs.Template.TemplateApi.SendTemplateMessage(valueItem.WorkQueueNo, valueItem.ToOpenID, valueItem.TemplateID, data, fromid,videoUrl);
                              </span><span style="color: rgba(0, 0, 255, 1)">if</span> (tempResult.errcode ==<span style="color: rgba(0, 0, 0, 1)"> ReturnCode.请求成功)
                              {
                                    Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{QUEUE_ROOMVISIRECORD},直播间{videoKey},发送成功,{valueItem.ToMemberID}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
                              }
                              </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
                              {
                                    Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{QUEUE_ROOMVISIRECORD},直播间{videoKey},发送失败,{tempResult.errmsg}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
                              }
                            }
                            </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
                            {
                              Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{QUEUE_ROOMVISIRECORD},直播间{videoKey},获取FromID为空,{valueItem.ToMemberID}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
                            }
                        }
                        </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
                        {
                            Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{QUEUE_ROOMVISIRECORD},直播间{videoKey},模板内容序列哈异常</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
                        }
                  }
                }
                </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">
                {
                  Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{QUEUE_ROOMVISIRECORD},直播间{videoKey},未找到直播间数据</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
                }</span></pre>
</div>
<p>&nbsp;</p>
<p>这里的场景是这样的:比如一个主播她创建了一个房间,设定开播的时间为某一天,为了给自己引流,他在微信群分享了小程序,这时只要有人点击了小程序链接点击预约就会记录与主播的关联,等到主播开播时,会群发下面预约的用户。是不是有点像群发功能,哈哈,大家有空可能尝试一下。</p>
<p>&nbsp;</p>
<p>注:这里利用了redis来存储fromid,你们也可以用其它的方式来存储,随便你来玩。</p>
<p>&nbsp;</p>
<p><strong>总结</strong></p>
<hr>
<p>&nbsp;人个觉得代码实现需求的过程并不复杂,主要是理解了原理与实现的过程后,就事半功倍。整个方案流程涉及到的关键词有表单、按钮、formId、模板消息、Redis等,主要需要前后端相关技术组合来实现整个方案。</p>
<p>&nbsp;</p>
<div>&nbsp;</div>
<div id="MySignature" style="display: block">
<div style="border: 1px dashed rgba(224, 224, 224, 1); padding: 15px 20px; background: rgba(229, 241, 244, 1); position: relative">
<p style="margin-bottom: 5px">作者:Dylan</p>
<p style="margin-bottom: 5px">公众号:dotNET名人堂(sharecore)</p>
<p style="margin-bottom: 5px">微信:tangguo_9669</p>
<p style="margin-bottom: 5px">QQ:.NET Core 技术交流(18362376)</p>
<p style="margin-bottom: 5px">出处:https://www.cnblogs.com/hailang8/</p>
<div>本文文章版权归作者和博客园共有,未经作者同意不得随意转载,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。如有问题或建议,请与我联系。</div>
<div>&nbsp;</div>
<div><img src="https://img2018.cnblogs.com/blog/679720/201908/679720-20190825214116095-648229977.jpg" alt=""></div>
</div>
</div>
<div>&nbsp;</div>
<div>我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3jpr0nagboo48</div>
<div>&nbsp;</div>

</div>
<div id="MySignature" role="contentinfo">
    <div id="MySignature" style="display: block">
<div style="border: #e0e0e0 1px dashed; padding: 15px 20px; padding-left: 20px; background: #e5f1f4; position: relative">
<p style="margin-bottom: 5px">作者:Dylan</p>
<p style="margin-bottom: 5px">公众号:dotNET名人堂(sharecore)</p>
<p style="margin-bottom: 5px">微信:tangguo_9669</p>
<p style="margin-bottom: 5px">QQ:.NET Core 技术交流(18362376)</p>
<p style="margin-bottom: 5px">出处:https://www.cnblogs.com/hailang8/</p>
<div>本文文章版权归作者和博客园共有,未经作者同意不得随意转载,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。如有问题或建议,请与我联系。</div>
<div>&nbsp;</div>
<div><img src="https://images.cnblogs.com/cnblogs_com/hailang8/1534502/o_gzh03.jpg" alt=""></div>


</div>


</div><br><br>
来源:https://www.cnblogs.com/hailang8/p/11415549.html
頁: [1]
查看完整版本: .NET Core 小程序开发零基础系列(2)——小程序服务通知(模板消息)