前段时间剁手了 PS4,在浏览商店时,发现官方商店真的不好用,主要是网络原因,次要是页面设计。所以就想自己做一个游戏查询的小程序,可以关注某个游戏,然后在这个游戏打折的时候发送通知给用户。最后发现有个很大的问题是:小程序没法直接给用户推送消息(当时还不知道模板消息),服务号才能。然后就用邮箱实现了通知功能,但是邮箱的局限实在是太大了(各大免费邮箱每天的发件数都很小,自己搭建的邮件服务器虽然没有发件限制,但是大概率会被放到垃圾箱)。
然后某天在微信小程序的管理后台发现了模板消息这个东西,查了会资料发现可以通过这个来实现消息推送。要给用户发送模板消息需要formId/prepay_id这样一个东西,这个东西是怎么来的呢?
formId:这个可以通过表单的提交来获取,需要在组件中设置属性report-submit="true",这样每次对这个表单的提交一次就会产生一个 formId.
prepay_id:这个是支付动作产生的,具体的我也不太清楚,毕竟个人小程序并不能支付.
下面具体来讲讲前后台的实现,前台使用 mpvue,后台使用 java
前台获取 formId既然可以通过 form 的 submit 操作来获取到 formId,那我们稍微拓展一下,将我们的小程序页面中所有用户能点击的部分都用 form,button 来包裹一下,这样用户感知不到有表单提交操作,我们也能获取大量的 formId。
注意不能用叠加的方式来一次点击获取多个 formId,这样方法已经不行了,获取到的都会是一样的。
获取一个模板要发送模板消息,首先要在小程序的管理后台上添加模板,步骤如下:
1.在模板库中选择一个模板
2.选择显示参数
选择要显示在消息中的参数,这里选择如下两个参数:
这样就有了一个模板可以用来发消息了,在我的模板中可以看到模板 id,和字段 id
获取 formIdformId 是通过表单提交来获取到了,为了获取足够多的 formId,可以将能够点击的组件(比如按钮,列表单元..)包裹在 form 中,这样用户在日常使用中就能够收集到足够多的 formId。下面以包裹一个有赞的按钮为例。因为小程序的限制,设置form-type属性的按钮必须为 form 组件的直接子节点,所以并不能够在 form 中使用自定义组件,并将form-type='submit'设置到自定义组件中。
template 部分如下:
<!-- 要获取formId,需要给form设置report-submit="true"的属性,然后在form-type="submit"的按钮上产生点击动作,才会触发表单提交的事件--formSubmit,进而获取到formId --> <form @submit="formSubmit" report-submit="true"> <button plain="true" form-type="submit" @click="back"> <van-button round type="primary" size="small" @click="back">返回</van-button> </button> <button plain="true" form-type="submit" @click="watchGame"> <van-button round type="danger" size="small">{{watchText}}</van-button> </button> <button plain="true" form-type="submit" open-type="share"> <van-button round type="info" size="small">分享</van-button> </button> </form>style 目的为了去除原生 button 的背景,边框啥的,把 button 当一个 div 来使用,然后在 button 中设置 form-type 和 click 属性,这样既不影响 formId 的属性,也对原有逻辑不产生任何影响。之所以将 click 放在 button 上是因为 button 内部的组件没法获取到点击事件。
formSubmit 代码如下:
formSubmit(e) { let item = { value: e.mp.detail.formId, expireTime: Date.now() + 7 * 24 * 60 * 60 * 1000 }; this.globalData.formIdList.push(item); },该函数是在表单提交时触发,用于获取 formId,将 formId 和这个 formId 的过期时间一起存到 globalData 全局数据中。然后找一个时机将这些 formId 发送给服务器保存起来就行了。
这里放上我的做法以供参考。
我是在每次发送 http 请求前检查是不是有 formId 需要发送到服务器,如果有就将这些数据 JSON 序列化后放到一个自定义 header 中,发送出去,具体代码如下(http 请求工具为:flyio):
var Fly = require("flyio/dist/npm/wx"); var fly = new Fly(); //在请求预处理中 fly.interceptors.request.use(request => { request.headers["jwt-token"] = wxUtil.getGlobalData("jwt-token"); //如果有formId就放到header里送过去 let formIdList = getApp().globalData.formIdList; if (formIdList.length > 0) { request.headers["formIdList"] = JSON.stringify(formIdList); getApp().globalData.formIdList = []; } if (request.method == "GET") { request.params["_t"] = new Date().getTime(); } return request; });下面将后台的实现,基于 Spring Boot.
后台处理 搜集 formId