PHP仿微信发红包领红包效果


Posted in PHP onOctober 30, 2016

近期项目需要在聊天的基础上新增红包功能,需求:仿微信(不含留言),但只能使用余额发红包。于是多次使用微信红包,了解各种交互界面及业务需求,如展示信息、分类(个人,群普通,群拼手气)、个数限制(100)、金额限制(200)、过期时间(24小时)等等,然后着手开发,下面提及的基本全是提供给app端的接口,毕竟我是phper。

一、设计数据表如下

CREATE TABLE `red_packet` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '用户id',
`for_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '发放对象(用户或群id)',
`pay_status` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '支付状态:0未支付,1已支付',
`type` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '类型:1、个人,2、群普通,3、群拼手气',
`intro` varchar(255) NOT NULL DEFAULT '' COMMENT '简介',
`number` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '个数',
`total_money` decimal(10,2) unsigned NOT NULL DEFAULT '0.0' COMMENT '总金额',
`single_money` decimal(10,2) unsigned NOT NULL DEFAULT '0.0' COMMENT '单个红包金额(群拼手气时为0)',
`return_money` decimal(10,2) unsigned NOT NULL DEFAULT '0.0' COMMENT '退还金额',
`is_cli_handle` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否经过cli退款处理:0否,1是',
`expend_time` mediumint(1) unsigned NOT NULL DEFAULT '0' COMMENT '领取消耗时间',
`add_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`pay_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '支付时间',
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `pay_status` (`pay_status`),
KEY `pay_time` (`pay_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='红包发放表';
CREATE TABLE `red_packet_log` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`rp_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '红包id',
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '领取人id',
`money` decimal(10,2) unsigned NOT NULL DEFAULT '0.0' COMMENT '领取金额',
`is_good` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否手气最佳:0否,1是',
`add_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '添加时间',
`update_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '领取时间',
PRIMARY KEY (`id`),
KEY `rp_id` (`rp_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='红包领取日志表';

二、发红包

PHP仿微信发红包领红包效果PHP仿微信发红包领红包效果

由于支付成功之后,红包就马上发到聊天界面了,所以在左图“塞钱进红包”时,就把红包信息插入 red_packet 表(支付状态未支付),并分配好金额、计算手气打乱后插入 red_packet_log 表(领取人和领取时间为空),右图“确认支付”成功之后,更新 red_packet 表的支付状态,然后发出红包。

三、领红包(这里只针对群红包进行分析)

PHP仿微信发红包领红包效果

PHP仿微信发红包领红包效果

领红包的各种前提校验请自己脑补,这里说一个抢群红包的并发问题(群里的几十个人抢几个红包),引入MQ来解决。在发红包的时候,先把红包个数依次写入MQ,比如发3个红包,就依次写入1、2、3。抢红包的时候从MQ取值,取得到数字说明你是第几个抢到红包,对应 red_packet_log 表里的第几个红包,接下来的就是更新 red_packet_log 表的领取人和领取时间,以及余额加钱以及记流水等业务处理了,然后返回领取结果;取不到数字的当然就说明没有抢到红包,直接出“手慢了”的界面。前期有考虑把 red_packet_log 表的主键写入MQ,可以省去排序拿第几条log记录,但这样会让“领取消耗时间”这个字段的更新更加麻烦;采用MQ存数字,则可以直接比对是否是最后一个红包(取到的数字等与红包个数),然后更新消耗时间。

微信红包的领取结果页(即查看手气页)有很多种:单个和群结果不一样,发红包的人和领红包的人看到的也不一样,单个和群红包过期之后提示不一样等等,这里不一一列举,基本都是根据界面查数据库而已。

四、需求变更,新增第三方支付

说到第三方支付,就要提及同步和异步回调,还有回调时间差。app端在同步回调成功的时候,就会把红包发出去了(app端的支付同步回调是直接调用callback的),如果此时异步回调慢了一两秒,那么用户就会抢到这个支付状态为0的红包。如果说让app端调用长连接接口去查异步回调是否已经成功,再发出红包,则用户体验比较差。

# 引入中间状态
ALTER TABLE `red_packet`
MODIFY COLUMN `pay_status` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '支付状态:0未支付,1已支付,2等待到账' AFTER `for_id`,
ADD COLUMN `pay_type` tinyint(1) NOT NULL DEFAULT 0 COMMENT '支付方式:0未知,1支付宝,2微信,3银联' AFTER `pay_status`,
ADD COLUMN `trade_no` varchar(30) NOT NULL DEFAULT '' COMMENT '第三方支付交易号' AFTER `pay_type`;
ALTER TABLE `red_packet_log`
ADD COLUMN `is_into_account` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否到账:0否,1是' AFTER `is_good`;

用户抢到红包的时候,根据 pay_status 来决定 is_into_account 的值;

同步回调到app端时,调用接口把支付状态 pay_status 变为2;

异步回调到服务端时,则把支付状态 pay_status 变为1,并查出 is_into_account=1 的 red_packet_log 记录进行处理。

但是上面这三步都要对 red_packet 的查询进行 FOR UPDATE 操作,不然会有执行时间和顺序问题,导致部分 red_packet_log 记录未到账 is_into_account=0;另外锁机制还会使得用户抢红包时变得很慢,因为要等锁释放。

改进如下:(全程不 FOR UPDATE)

用户抢到红包的时候,根据 pay_status 来决定 is_into_account 的值;

同步回调到app端时,调用接口把支付状态 pay_status 变为2;

异步回调到服务端时,则把支付状态 pay_status 变为1,并把红包id(red_packet主键)放入MQ;

后台自动脚本,从MQ拿到红包id之后,把该红包 is_into_account=0 的记录进行处理,然后再延迟5秒把红包id再次写入MQ,进行二次处理,确保数据全部到账。

五、红包过期退还

这里就一个自动脚本,根据 red_packet 表的 pay_time 判断是否超过24小时且没领完的钱,退回用户余额。

PHP 相关文章推荐
PHP setcookie指定domain参数后,在IE下设置cookie失效的解决方法
Sep 09 PHP
腾讯QQ微博API接口获取微博内容
Oct 30 PHP
php 字符串压缩方法比较示例
Jan 23 PHP
php导出csv格式数据并将数字转换成文本的思路以及代码分享
Jun 05 PHP
php使用pack处理二进制文件的方法
Jul 03 PHP
php提示Failed to write session data错误的解决方法
Dec 17 PHP
PHP strtotime函数用法、实现原理和源码分析
Feb 04 PHP
PHP的APC模块实现上传进度条
Oct 27 PHP
PHP实现十进制、二进制、八进制和十六进制转换相关函数用法分析
Apr 25 PHP
PHP命令空间namespace及use的用法小结
Nov 27 PHP
PHP后台备份MySQL数据库的源码实例
Mar 18 PHP
php设计模式之组合模式实例详解【星际争霸游戏案例】
Mar 27 PHP
PHPCMS忘记后台密码的解决办法
Oct 30 #PHP
php set_include_path函数设置 include_path 配置选项
Oct 30 #PHP
php 截取utf-8格式的字符串实例代码
Oct 30 #PHP
php mysql like 实现多关键词搜索的方法
Oct 29 #PHP
PHP请求远程地址设置超时时间的解决方法
Oct 29 #PHP
浅谈php处理后端&接口访问超时的解决方法
Oct 29 #PHP
完美解决phpexcel导出到xls文件出现乱码的问题
Oct 29 #PHP
You might like
ThinkPHP之getField详解
2014/06/20 PHP
PHP函数http_build_query使用详解
2014/08/20 PHP
PHP常用字符串操作函数实例总结(trim、nl2br、addcslashes、uudecode、md5等)
2016/01/09 PHP
php similar_text()函数的定义和用法
2016/05/12 PHP
JavaScript 异步调用框架 (Part 5 - 链式实现)
2009/08/04 Javascript
javascript 动态修改样式和层叠样式表代码
2010/04/27 Javascript
在HTML代码中使用JavaScript代码的例子
2014/10/16 Javascript
jquery实现邮箱自动填充提示功能
2015/11/17 Javascript
jQuery实现百叶窗焦点图动画效果代码分享(附源码下载)
2016/03/14 Javascript
jQuery的deferred对象使用详解
2016/09/25 Javascript
jQuery Ztree行政地区树状展示(点击加载)
2016/11/09 Javascript
nodejs基础知识
2017/02/03 NodeJs
在Vue组件化中利用axios处理ajax请求的使用方法
2017/08/25 Javascript
使用vue-cli脚手架工具搭建vue-webpack项目
2019/01/14 Javascript
JavaScript深入V8引擎以及编写优化代码的5个技巧
2019/06/24 Javascript
vue-cli4.0多环境配置变量与模式详解
2020/12/30 Vue.js
Python中请使用isinstance()判断变量类型
2014/08/25 Python
在Python中使用NLTK库实现对词干的提取的教程
2015/04/08 Python
在Linux系统上安装Python的Scrapy框架的教程
2015/06/11 Python
用python编写第一个IDA插件的实例
2018/05/29 Python
让代码变得更易维护的7个Python库
2018/10/09 Python
Python使用combinations实现排列组合的方法
2018/11/13 Python
Django中的cookie和session
2019/08/27 Python
Python气泡提示与标签的实现
2020/04/01 Python
pycharm下pyqt4安装及环境配置的教程
2020/04/24 Python
Python decimal模块使用方法详解
2020/06/08 Python
超级实用的8个Python列表技巧
2020/08/24 Python
Python字符串对齐、删除字符串不需要的内容以及格式化打印字符
2021/01/23 Python
实例讲解使用SVG制作loading加载动画的方法
2016/04/05 HTML / CSS
特罗佩亚包官方网站:Tropea
2017/01/03 全球购物
从当地商店送来的杂货:Instacart
2018/08/19 全球购物
市场开发计划书
2014/05/07 职场文书
人事行政主管岗位职责
2015/04/09 职场文书
SpringCloud的JPA连接PostgreSql的教程
2021/06/26 Java/Android
利用Python将list列表写入文件并读取的方法汇总
2022/03/25 Python
吉利入股戴姆勒后smart“长大了”
2022/04/21 数码科技