PHP仿微信發(fā)紅包領(lǐng)紅包效果
近期項(xiàng)目需要在聊天的基礎(chǔ)上新增紅包功能,需求:仿微信(不含留言),但只能使用余額發(fā)紅包。于是多次使用微信紅包,了解各種交互界面及業(yè)務(wù)需求,如展示信息、分類(個(gè)人,群普通,群拼手氣)、個(gè)數(shù)限制(100)、金額限制(200)、過(guò)期時(shí)間(24小時(shí))等等,然后著手開發(fā),下面提及的基本全是提供給app端的接口,畢竟我是phper。
一、設(shè)計(jì)數(shù)據(jù)表如下
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 '發(fā)放對(duì)象(用戶或群id)', `pay_status` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '支付狀態(tài):0未支付,1已支付', `type` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '類型:1、個(gè)人,2、群普通,3、群拼手氣', `intro` varchar(255) NOT NULL DEFAULT '' COMMENT '簡(jiǎn)介', `number` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '個(gè)數(shù)', `total_money` decimal(10,2) unsigned NOT NULL DEFAULT '0.0' COMMENT '總金額', `single_money` decimal(10,2) unsigned NOT NULL DEFAULT '0.0' COMMENT '單個(gè)紅包金額(群拼手氣時(shí)為0)', `return_money` decimal(10,2) unsigned NOT NULL DEFAULT '0.0' COMMENT '退還金額', `is_cli_handle` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否經(jīng)過(guò)cli退款處理:0否,1是', `expend_time` mediumint(1) unsigned NOT NULL DEFAULT '0' COMMENT '領(lǐng)取消耗時(shí)間', `add_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '創(chuàng)建時(shí)間', `pay_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '支付時(shí)間', PRIMARY KEY (`id`), KEY `user_id` (`user_id`), KEY `pay_status` (`pay_status`), KEY `pay_time` (`pay_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='紅包發(fā)放表'; 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 '領(lǐng)取人id', `money` decimal(10,2) unsigned NOT NULL DEFAULT '0.0' COMMENT '領(lǐng)取金額', `is_good` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否手氣最佳:0否,1是', `add_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '添加時(shí)間', `update_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '領(lǐng)取時(shí)間', PRIMARY KEY (`id`), KEY `rp_id` (`rp_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='紅包領(lǐng)取日志表';
二、發(fā)紅包


由于支付成功之后,紅包就馬上發(fā)到聊天界面了,所以在左圖“塞錢進(jìn)紅包”時(shí),就把紅包信息插入 red_packet 表(支付狀態(tài)未支付),并分配好金額、計(jì)算手氣打亂后插入 red_packet_log 表(領(lǐng)取人和領(lǐng)取時(shí)間為空),右圖“確認(rèn)支付”成功之后,更新 red_packet 表的支付狀態(tài),然后發(fā)出紅包。
三、領(lǐng)紅包(這里只針對(duì)群紅包進(jìn)行分析)


領(lǐng)紅包的各種前提校驗(yàn)請(qǐng)自己腦補(bǔ),這里說(shuō)一個(gè)搶群紅包的并發(fā)問(wèn)題(群里的幾十個(gè)人搶幾個(gè)紅包),引入MQ來(lái)解決。在發(fā)紅包的時(shí)候,先把紅包個(gè)數(shù)依次寫入MQ,比如發(fā)3個(gè)紅包,就依次寫入1、2、3。搶紅包的時(shí)候從MQ取值,取得到數(shù)字說(shuō)明你是第幾個(gè)搶到紅包,對(duì)應(yīng) red_packet_log 表里的第幾個(gè)紅包,接下來(lái)的就是更新 red_packet_log 表的領(lǐng)取人和領(lǐng)取時(shí)間,以及余額加錢以及記流水等業(yè)務(wù)處理了,然后返回領(lǐng)取結(jié)果;取不到數(shù)字的當(dāng)然就說(shuō)明沒(méi)有搶到紅包,直接出“手慢了”的界面。前期有考慮把 red_packet_log 表的主鍵寫入MQ,可以省去排序拿第幾條log記錄,但這樣會(huì)讓“領(lǐng)取消耗時(shí)間”這個(gè)字段的更新更加麻煩;采用MQ存數(shù)字,則可以直接比對(duì)是否是最后一個(gè)紅包(取到的數(shù)字等與紅包個(gè)數(shù)),然后更新消耗時(shí)間。
微信紅包的領(lǐng)取結(jié)果頁(yè)(即查看手氣頁(yè))有很多種:?jiǎn)蝹€(gè)和群結(jié)果不一樣,發(fā)紅包的人和領(lǐng)紅包的人看到的也不一樣,單個(gè)和群紅包過(guò)期之后提示不一樣等等,這里不一一列舉,基本都是根據(jù)界面查數(shù)據(jù)庫(kù)而已。
四、需求變更,新增第三方支付
說(shuō)到第三方支付,就要提及同步和異步回調(diào),還有回調(diào)時(shí)間差。app端在同步回調(diào)成功的時(shí)候,就會(huì)把紅包發(fā)出去了(app端的支付同步回調(diào)是直接調(diào)用callback的),如果此時(shí)異步回調(diào)慢了一兩秒,那么用戶就會(huì)搶到這個(gè)支付狀態(tài)為0的紅包。如果說(shuō)讓app端調(diào)用長(zhǎng)連接接口去查異步回調(diào)是否已經(jīng)成功,再發(fā)出紅包,則用戶體驗(yàn)比較差。
# 引入中間狀態(tài) ALTER TABLE `red_packet` MODIFY COLUMN `pay_status` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '支付狀態(tài):0未支付,1已支付,2等待到賬' AFTER `for_id`, ADD COLUMN `pay_type` tinyint(1) NOT NULL DEFAULT 0 COMMENT '支付方式:0未知,1支付寶,2微信,3銀聯(lián)' AFTER `pay_status`, ADD COLUMN `trade_no` varchar(30) NOT NULL DEFAULT '' COMMENT '第三方支付交易號(hào)' 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`;
用戶搶到紅包的時(shí)候,根據(jù) pay_status 來(lái)決定 is_into_account 的值;
同步回調(diào)到app端時(shí),調(diào)用接口把支付狀態(tài) pay_status 變?yōu)?;
異步回調(diào)到服務(wù)端時(shí),則把支付狀態(tài) pay_status 變?yōu)?,并查出 is_into_account=1 的 red_packet_log 記錄進(jìn)行處理。
但是上面這三步都要對(duì) red_packet 的查詢進(jìn)行 FOR UPDATE 操作,不然會(huì)有執(zhí)行時(shí)間和順序問(wèn)題,導(dǎo)致部分 red_packet_log 記錄未到賬 is_into_account=0;另外鎖機(jī)制還會(huì)使得用戶搶紅包時(shí)變得很慢,因?yàn)橐孺i釋放。
改進(jìn)如下:(全程不 FOR UPDATE)
用戶搶到紅包的時(shí)候,根據(jù) pay_status 來(lái)決定 is_into_account 的值;
同步回調(diào)到app端時(shí),調(diào)用接口把支付狀態(tài) pay_status 變?yōu)?;
異步回調(diào)到服務(wù)端時(shí),則把支付狀態(tài) pay_status 變?yōu)?,并把紅包id(red_packet主鍵)放入MQ;
后臺(tái)自動(dòng)腳本,從MQ拿到紅包id之后,把該紅包 is_into_account=0 的記錄進(jìn)行處理,然后再延遲5秒把紅包id再次寫入MQ,進(jìn)行二次處理,確保數(shù)據(jù)全部到賬。
五、紅包過(guò)期退還
這里就一個(gè)自動(dòng)腳本,根據(jù) red_packet 表的 pay_time 判斷是否超過(guò)24小時(shí)且沒(méi)領(lǐng)完的錢,退回用戶余額。
- php數(shù)組函數(shù)序列之a(chǎn)rray_pop() - 刪除數(shù)組中的最后一個(gè)元素
- php array_pop()數(shù)組函數(shù)將數(shù)組最后一個(gè)單元彈出(出棧)
- PHP遞歸獲取目錄內(nèi)所有文件的實(shí)現(xiàn)方法
- PHP之十六個(gè)魔術(shù)方法詳細(xì)介紹
- php 實(shí)現(xiàn)一個(gè)字符串加密解密的函數(shù)實(shí)例代碼
- PHP用戶驗(yàn)證和標(biāo)簽推薦的簡(jiǎn)單使用
- PHP實(shí)現(xiàn)小偷程序?qū)嵗?/a>
- 利用php做服務(wù)器和web前端的界面進(jìn)行交互
- php將服務(wù)端的文件讀出來(lái)顯示在web頁(yè)面實(shí)例
- PHPCMS忘記后臺(tái)密碼的解決辦法
- php array_pop 刪除數(shù)組最后一個(gè)元素實(shí)例
相關(guān)文章
使用Git實(shí)現(xiàn)Laravel項(xiàng)目的自動(dòng)化部署
這篇文章主要介紹了使用Git實(shí)現(xiàn)Laravel項(xiàng)目的自動(dòng)化部署,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
Laravel框架實(shí)現(xiàn)的批量刪除功能示例
這篇文章主要介紹了Laravel框架實(shí)現(xiàn)的批量刪除功能,結(jié)合實(shí)例形式分析了Laravel框架批量刪除功能相關(guān)的前端界面布局及后臺(tái)控制器實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-01-01
php把時(shí)間戳轉(zhuǎn)換成多少時(shí)間之前函數(shù)的實(shí)例
下面小編就為大家?guī)?lái)一篇php把時(shí)間戳轉(zhuǎn)換成多少時(shí)間之前函數(shù)的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11
深入mysql_fetch_row()與mysql_fetch_array()的區(qū)別詳解
本篇文章是對(duì)mysql_fetch_row()與mysql_fetch_array()的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
Laravel5.1 框架模型查詢作用域定義與用法實(shí)例分析
這篇文章主要介紹了Laravel5.1 框架模型查詢作用域定義與用法,結(jié)合實(shí)例形式分析了laravel5.1定義一個(gè)查詢作用域及動(dòng)態(tài)的查詢作用域相關(guān)操作技巧,需要的朋友可以參考下2020-01-01
php制作動(dòng)態(tài)隨機(jī)驗(yàn)證碼
這篇文章主要介紹了php制作動(dòng)態(tài)隨機(jī)驗(yàn)證碼的方法的相關(guān)資料,需要的朋友可以參考下2015-02-02

