微信小程序发送订阅消息|模板消息
~~~~ 本文仅针对新手小白同学,老鸟请略过 ~~~
对于初学者,找文档也是个麻烦事,因为文档太大了。故本文把官方文档做了提炼和引用,在每一个接口处
目录
一、需求场景
二、新手的几个问题
三、微信小程序准备知识
1、关于订阅
1)订阅长什么样?
2)为什么要订阅?
3)什么时候提示订阅?
4)订阅类型
5)订阅后用户如何查看或管理
2、简要说明几个参数
四、配置消息模板
五、获取重要的参数
1、获取openid
第1步:前台获取 code
第2步:后台获取 openid
2、获取access_token
六、引导用户完成订阅
1、调起客户端小程序订阅消息界面
2、查询用户当前设置(非必须,含订阅信息)
七、阶段小结
八、步入正题发送消息
九、功能扩展与项目集成
1、若干问题
2、简单设计参考
一、需求场景
在微信小程序项目中,经常有消息需要实时发送用户。如流程任务审核、付款到账、交易通知、工单提醒等。有两种实现方法:
一、微信公众号绑定小程序,用户关注公众号。系统发送消息到微信公众号。这种情况需要你额外准备一个公众号。
二、用户订阅小程序通知,订阅后系统直接发消息到微信小程序。消息在” 微信->服务号->通知“ 查看。
本文采用并推荐使用第二种方法。
二、新手的几个问题
Q1、系统如何识别某用户的微信,如系统用户名“张三”,对应微信标识是哪个?
Q2、微信是否允许我给张三发通知?我能够一直给张三发通知吗?
Q3、我是否可以自定义内容模板?别人定义的模板我想用,但不需要那么多参数怎么办?
Q4、用户点击我发的通知消息,能够跳转到对应的业务办理页面吗?
这些问题会贯穿以下内容
三、微信小程序准备知识
1、关于订阅
1)订阅长什么样?
PS: 大家几乎天天用小程序,每个新小程序都会提示,见到此图并不会陌生
2)为什么要订阅?
微信规定,只有用户自主订阅后,系统后台才能发送消息给用户。很好理解,防止垃圾信息骚扰用户。
3)什么时候提示订阅?
我们先从产品体验角度,讨论下什么时候弹出订阅界面比较合适。
A. 如果是开放式产品不需要严格的权限(如商城、点餐等),用户需要先浏览体验下内容等。那么可以在用户点击下单,或需要确认身份(注册/登录系统)后,触发弹出订阅界面。
B. 如果是权限很严格的,小程序首先进行登录界面,那么登录成功后,跳到主页前适合触发弹出订阅界面。
4)订阅类型
一次订阅:用户订阅后,在任意时间发一次消息给用户。不能发第二次。那么如何发多条消息呢?需要用户在弹出的订阅界面:
勾选 “○总是保持以上选择” 即可。
长期订阅:用户订阅后,可长期发送多条信息。但对行业与资质要求较高,准入门槛高,除非你是toG的或者民生类、教育类等等。
5)订阅后用户如何查看或管理
旁白:如果用户未订阅,系统不要浪费表情和系统资源为其发送。
用户可能从来没用这个小程序,也可能是订阅时给拒绝了。总之ta收不到。
所以我们系统后台
1、需要记录用户的订阅行为,细化到订阅了哪个模板。
2、甚至取消时,我们也可接收到微信系统通知,随时更新标记。
2、简要说明几个参数
appid、app_secret: 系统为每个小程序分配的唯一标识,和密钥。登录小程序后台:管理->开发管理->开发设置,查看并妥善保存。
code: 微信分配的临时登录凭证
access_token: 小程序全局唯一后台接口调用凭据,token有效期为7200s,过期了需要调接口刷新。
openId: 一个微信号关注了一个公众号/小程序,给该微信用户生成的唯一编号就是openId。这是我们能够找到用户的重要标识。
unionId: 一个微信开放平台下的多个应用,包括多个公众号/小程序等,针对同一个微信用户生成的unionId是相同的。
templageId: 开发者在小程序后台,选取或申请了模板后,生成的模板唯一标识。
以上这些参数,是微信生态体系的核心和基础参数。不仅仅是发送消息使用,在其它任意调用API之处均需要使用。
四、配置消息模板
登录微信小程序后台,基础功能 -> 订阅消息,优先从公共模板库中查找接近自己的模板,并从中选择关键词。
从我的模板中,复制模板ID使用。订阅以及消息发送里,都需要模板ID
五、获取重要的参数
我们看微信官方文档,发送消息需要以下参数,我们倒推法逐一得到这些参数:
发送订阅消息 | 微信开放文档微信开发者平台文档https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/sendMessage.html
1、获取openid
第1步:前台获取 code
twx.login(Object object) | 微信开放文档微信开发者平台文档https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html
wx.login({ success (res) { if (res.code) { //发起网络请求 wx.request({ url: \'https://example.com/onLogin\', data: { code: res.code } }) } else { console.log(\'登录失败!\' + res.errMsg) } }})
uniapp可以这样用
uni.login(OBJECT) | uni-app官网uni-app,uniCloud,serverless,uni.login(OBJECT),App平台支持的登录方式,小程序平台支持的登录方式,web平台支持的登录方式,OBJECT 参数说明,注意事项,uni.getLoginCode(OBJECT),uni.checkSession,uni.gehttps://uniapp.dcloud.net.cn/api/plugins/login.html#login
uni.login({ provider: \'weixin\', //使用微信登录 success: function (loginRes) { console.log(loginRes.authResult); }});
第2步:后台获取 openid
小程序登录 | 微信开放文档微信开发者平台文档https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html
GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code respone:{\"openid\":\"xxxxxx\",\"session_key\":\"xxxxx\",\"unionid\":\"xxxxx\",\"errcode\":0,\"errmsg\":\"xxxxx\"}
public static final String WECHAT_OPENID_URL = \"https://api.weixin.qq.com/sns/jscode2session?\"; /** * 获取微信 openId unionId * * @param appId * @param code * @return */ public WechatSession code2Session(String companyNo, String appId, String code) { String appSecret = getAppSecret(companyNo, appId); StringBuffer request = new StringBuffer(); request.append(WECHAT_OPENID_URL); request.append(\"appid=\").append(appId).append(\"&\"); request.append(\"secret=\").append(appSecret).append(\"&\"); request.append(\"js_code=\").append(code).append(\"&\"); request.append(\"grant_type=\").append(\"authorization_code\"); //log.info(\"wechat request jscode2session url={}\", request); try { String response = HttpUtil.get(request.toString()); log.info(\"wechat response: {}\", response); JSONObject result = JSON.parseObject(response); Integer errCode = result.getInteger(\"errcode\"); if(errCode == null){ WechatSession session = new WechatSession(); session.setOpenId(result.getString(\"openid\")); session.setUnionId(result.getString(\"unionid\")); session.setSessionKey(result.getString(\"session_key\")); return session; } } catch (Exception e) { e.printStackTrace(); return null; } return null; }
2、获取access_token
获取接口调用凭据 | 微信开放文档微信开发者平台文档https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html
GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRETresponse{\"access_token\":\"ACCESS_TOKEN\",\"expires_in\":7200}
public static final String WECHAT_TOKEN_URL = \"https://api.weixin.qq.com/cgi-bin/token?\"; /** * 获取微信 access_token * * @param appId * @param companyNo * @return */ public String acccessToken(String companyNo, String appId) { String appSecret = getAppSecret(companyNo, appId); StringBuffer request = new StringBuffer(); request.append(WECHAT_TOKEN_URL); request.append(\"appid=\").append(appId).append(\"&\"); request.append(\"secret=\").append(appSecret).append(\"&\"); request.append(\"grant_type=\").append(\"client_credential\"); //log.info(\"wechat request token url={}\", request); try { String response = HttpUtil.get(request.toString()); log.info(\"wechat response: {}\", response); JSONObject result = JSON.parseObject(response); Integer errCode = result.getInteger(\"errcode\"); if(errCode == null){ String accessToken = result.getString(\"access_token\"); return accessToken; } } catch (Exception e) { e.printStackTrace(); return null; } return null; }
六、引导用户完成订阅
1、调起客户端小程序订阅消息界面
wx.requestSubscribeMessage(Object object) | 微信开放文档微信开发者平台文档https://developers.weixin.qq.com/miniprogram/dev/api/open-api/subscribe-message/wx.requestSubscribeMessage.html
wx.requestSubscribeMessage({ tmplIds: [\'i6Mr7Qlw-w3KAxRz0ol84rPTXmvCoFwJgIHOw1tbiAI\',\'nq42vjDBz4FgSRdHeYY32qYrfM1i16cf0uTSRGpr96M\'], success (res) { //可传给后台保存 }})success回调参数{ errMsg: \"requestSubscribeMessage:ok\", zun-LzcQyW-edafCVvzPkK4de2Rllr1fFpw2A_x0oXE: \"accept\", abc-aaaa-bcUUwjllajcQyW-edafCVvzPkK4de2a: \"reject\"}
uniapp可以这样用
uni.requestSubscribeMessage(Object object) | uni-app官网uni-app,uniCloud,serverless,uni.requestSubscribeMessage(Object object)https://uniapp.dcloud.net.cn/api/other/requestSubscribeMessage.html#requestsubscribemessage
uni.requestSubscribeMessage({ tmplIds: [\'\'], success (res) { }})
调用成功后,最好送到后台进行保存。不然你可能需要如下方法去反查。。。
2、查询用户当前设置(非必须,含订阅信息)
wx.getSetting(Object object) | 微信开放文档微信开发者平台文档https://developers.weixin.qq.com/miniprogram/dev/api/open-api/setting/wx.getSetting.html
wx.getSetting({ withSubscriptions: true, success (res) { console.log(res.authSetting) // res.authSetting = { // \"scope.userInfo\": true, // \"scope.userLocation\": true // } console.log(res.subscriptionsSetting) // res.subscriptionsSetting = { // mainSwitch: true, // 订阅消息总开关 // itemSettings: { // 每一项开关 // SYS_MSG_TYPE_INTERACTIVE: \'accept\', // 小游戏系统订阅消息 // SYS_MSG_TYPE_RANK: \'accept\' // zun-LzcQyW-edafCVvzPkK4de2Rllr1fFpw2A_x0oXE: \'reject\', // 普通一次性订阅消息 // ke_OZC_66gZxALLcsuI7ilCJSP2OJ2vWo2ooUPpkWrw: \'ban\', // } // } }})
七、阶段小结
通过以上步骤,获得了发送消息的必要条件。有配置的工作,也有代码的工作。代码有台前调用微信的,还有后台调用微信的,注意区分。
八、步入正题发送消息
发送订阅消息 | 微信开放文档微信开发者平台文档https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/sendMessage.html
/*官方给出的模板内容格式姓名: {{name01.DATA}}金额: {{amount01.DATA}}行程: {{thing01.DATA}}日期: {{date01.DATA}}*/{ \"touser\": \"OPENID\", \"template_id\": \"TEMPLATE_ID\", \"page\": \"index\", \"data\": { \"name01\": { \"value\": \"某某\" }, \"amount01\": { \"value\": \"¥100\" }, \"thing01\": { \"value\": \"广州至北京\" } , \"date01\": { \"value\": \"2018-01-01\" } }}
public static final String WECHAT_SENDMSG_URL = \"https://api.weixin.qq.com/cgi-bin/message/subscribe/send?\"; /** * 发送订阅消息 * @param accessToken * @param templateId * @param page * @param openId * @param data * @return */ public boolean sendMessage(String accessToken, String templateId, String page, String openId, Object data){ JSONObject param = new JSONObject(); param.put(\"template_id\", templateId); param.put(\"page\", page); //用户点击消息,跳转的页面,可携带参数 param.put(\"touser\", openId); param.put(\"data\", data); param.put(\"miniprogram_state\", \"developer\"); param.put(\"lang\", \"zh_CN\"); log.info(\"wechat request sendMessage param={}\", param.toJSONString()); String url = WECHAT_SENDMSG_URL + \"access_token=\" + accessToken; try { String response = HttpUtil.post(url, param.toJSONString()); log.info(\"wechat response: {}\", response); JSONObject result = JSON.parseObject(response); Integer errCode = result.getInteger(\"errcode\"); if(errCode == 0){ return true; } } catch (Exception e) { e.printStackTrace(); } return false; }
九、功能扩展与项目集成
1、若干问题
1)、如何通过微信OpenId找到系统用户?最好不要侵入原来的用户体系设计
参考思路:对于后台已经开通的用户,在首次登录时引导用户输入用户名、密码或其它标识,小程序客户端口自动获取到openid,完成openid与系统用户的绑定。
2)、access_token获取后保存到哪里?怎么判断过期了,如何刷新?
将access_token保存到微信应用表中,或redis缓存中。根据获得时间+7200秒,设置过期时间
3)、用户是否订阅了某个消息模板?只有用户成功订阅,系统才发送给该用户消息
将订阅信息保存到微信用户表中,订阅完成时保存这些信息。如果用户在订阅后期,主动关闭了订阅,微信会发信息给平台。可以随时更新订阅信息
4)、业务系统:某类消息模板需要发送到哪些用户?
将某类业务(对应一个模板),与需要发送的系统用户或微信用户,通过管理系统配置并记录。当然也可以通过某类规则,完成多个用户的关联。
2、简单设计参考
1) t_wechat_app 微信应用表
字段名称
字段描述
ID
主键ID
create_by
创建人
create_time
创建日期
update_by
更新人
update_time
更新日期
app_id
应用编号
access_token
令牌
token_exp_time
令牌失效时间
remarks
备注信息
2) t_wechat_user 微信用户表
字段名称
字段描述
ID
主键ID
create_by
创建人
create_time
创建日期
update_by
更新人
update_time
更新日期
app_id
应用编号
openid
OPENID
unionid
UNIONID
nick_name
用户昵称
avatar_url
头像
session_key
SessionKey
subscribe_template
订阅消息模板
sys_user_id
系统用户ID
username
登录用户名
status
状态
remarks
备注信息
3) t_wechat_message_user 微信消息成员表
字段名称
字段描述
ID
主键ID
create_by
创建人
create_time
创建日期
update_by
更新人
update_time
更新日期
company_no
公司编号
app_id
应用编号
template_id
消息模板
customer_id
所属商户
sys_user_ids
发送用户
status
状态
remarks
备注