本文主要分享了如何设计一个发送微信订阅消息功能。
一、总结简述
1.封装微信订阅消息模板获取和发送代码
2.提供存储方案,表结构设计
3.提供真实生产项目代码案例,实现异步机制、定时发送、超时取消发送等功能
4.文末提供代码仓库,有兴趣的小伙伴可以fork代码
二、架构设计
开发订阅消息分2步:
1)记录用户授权
2)发送订阅消息
思考1:是否一定需要记录订阅消息模板的用户授权次数?
其实发送订阅消息跟发送短信一样,只不过多了个需要用户授权才能发送成功。像程序单次触发订阅消息,其实是不需要知道目标用户有没有授权的,我们只管无脑发,如果用户有授权就成功,没授权就失败。
思考2:那为什么要记录授权次数呢?
使用场景:按授权记录找到用户。比如需要筛选订阅了某个模板的用户,给这些用户发订阅消息。因为这里给所有用户无脑发就行不通了,因为你的用户量可能百万甚至千万级别的,无效发送会导致性能问题。
思考3:订阅消息有哪些触发时机呢?
1)用户完成了某个操作之后触发。比如拼团,团员参团后给团长发送1个订阅消息告知
2)定时任务触发。比如优惠券过期提醒,每天或每周扫描一下是否有即将过期的优惠券,有则发送
3)用户完成某个操作之后,针对这个操作预备一个未来发送的订阅消息。比如用户领取了1张优惠券,针对该优惠券在过期前n天给用户发送1个提醒消息
三、代码实现
1.数据库表结构设计
CREATE TABLE `subscribe_template` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`pri_tmpl_id` varchar(64) NOT NULL DEFAULT '' COMMENT '添加至账号下的模板 id,发送小程序订阅消息时所需',
`title` varchar(32) NOT NULL DEFAULT '' COMMENT '模版标题',
`content` varchar(255) NOT NULL DEFAULT '' COMMENT '模板内容',
`example` varchar(255) NOT NULL DEFAULT '' COMMENT '模板内容示例',
`type` int(11) NOT NULL DEFAULT '0' COMMENT '模版类型,2 为一次性订阅,3 为长期订阅',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `uniq_pritmplid` (`pri_tmpl_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅消息模板';
CREATE TABLE `subscribe_type_template_config` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`type` varchar(32) NOT NULL DEFAULT '' COMMENT '业务类型',
`param_index` varchar(32) NOT NULL DEFAULT '' COMMENT '参数索引(逗号分隔,空代表按顺序)',
`template_code` varchar(64) NOT NULL DEFAULT '' COMMENT '模板编码(subscribe_template.pri_tmpl_id)',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `uniq_type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅消息业务-模板配置';
CREATE TABLE `subscribe_group_type` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`group` varchar(32) NOT NULL DEFAULT '' COMMENT '订阅组',
`types` varchar(128) NOT NULL COMMENT '业务类型(多个英文逗号分隔,最多3个)',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `uniq_group` (`group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅消息-订阅组';
CREATE TABLE `subscribe_template_grant` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`openid` varchar(32) NOT NULL COMMENT 'openid',
`template_code` varchar(64) NOT NULL COMMENT '模板编码(subscribe_template.pri_tmpl_id)',
`total_num` int(11) NOT NULL DEFAULT '0' COMMENT '授权总次数',
`use_num` int(11) NOT NULL DEFAULT '0' COMMENT '已使用次数',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `uniq_openid_templatecode` (`openid`,`template_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅消息-授权记录';
CREATE TABLE `subscribe_task` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`type` varchar(32) NOT NULL COMMENT '业务类型',
`plan_send_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '计划发送时间',
`over_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '超时取消发送时间',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅消息发送任务';
CREATE TABLE `subscribe_task_detail` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`task_id` int(11) unsigned NOT NULL COMMENT 'subscribe_task.id',
`openid` varchar(32) NOT NULL COMMENT 'openid',
`page` varchar(32) NOT NULL COMMENT '跳转页面',
`template_param_json` varchar(255) DEFAULT NULL COMMENT '模板参数json',
`plan_send_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '计划发送时间',
`actual_send_time` datetime DEFAULT NULL COMMENT '实际发送时间',
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '状态(1:待发送,2:待定时发送,11:发送MQ成功,12:MQ消费成功,21:请求成功,22:请求失败,31:取消发送)',
`template_code` varchar(64) NOT NULL DEFAULT '' COMMENT '模板编码(subscribe_template.pri_tmpl_id)',
`content` varchar(255) DEFAULT NULL COMMENT '订阅消息内容',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_taskid` (`task_id`),
KEY `idx_openid` (`openid`),
KEY `idx_plansendtime_status` (`plan_send_time`,`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅消息发送任务明细';
表说明:
subscribe_template:直接同步微信的订阅消息模板,核心是模板ID和模板内容2个字段
subscribe_type_template_config:定于业务与模板ID的关系,一般某个业务会写死在代码中,利用这个表灵活配置某个业务发送的模板消息
subscribe_group_type:订阅消息1次最多订阅3个模板,前端根据group找到对应业务,从而找到需要订阅的模板组
subscribe_template_grant:用户每授权1次就记录,主要用于筛选订阅了某个模板的用户,给这些用户发消息的场景(不用到这种场景可不记录)
subscribe_task、subscribe_task_detail:订阅消息任务,可以理解为每次发送订阅消息都是1个订阅消息任务,每个订阅消息任务可以给多个用户发送订阅消息,营销信息常用,支持即时发送和定时发送
数据样例说明:
订阅消息模板
1)pri_teml_id即template_code,代码中根据pri_teml_id查询content,发送时解析传参
订阅消息业务-模板配置
1)代码中会写死type,跟据type查询到template_code,param_index用于代码中传递的参数数量与模板参数数量不匹配时用到,比如代码中写了传递4个参数,但是更换的模板只需要3个参数,默认情况下会取前3个参数填入,但如果不想要的参数是第2个,则填写0,2,3
订阅消息-订阅组
1)这里order_finish会写死到前端,通过值查询订阅的业务是3个,再通过type查询template_code返回给前端,进行订阅窗口的拉起
2.将subscribe_template、
subscribe_type_template_config、subscribe_group_type都做成后台配置功能,这里就不细讲了
3.核心代码展示
1)封装binarywang 微信SDK发送订阅消息代码
2)封装binarywang 微信SDK获取订阅消息模板代码(用于程序同步模板,无需手动添加)
3)生产者核心代码
4)消费者核心代码
怎么样?如果你觉得有用的话,还不快快收藏起来!!!
附:涉及的代码目录
github: https://github.com/897665787/springcloud-template
gitee:https://gitee.com/jq_di/springcloud-template
springcloud-template
└── template-tool
└──controller
└── SubscribeController -- 订阅消息相关API
└── subscribe
└── AsyncSubscribeSender -- 异步发送 订阅消息,MQ生产者逻辑
└── SubscribeSenderConsumer -- 异步发送 订阅消息,MQ消费者逻辑
└── SubscribeType -- 用于解决触发时机3的场景
└── sql
└── tool
└── 订阅消息设计相关表.sql