日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

聲明:本文來自于微信公眾號(hào) JavaGuide (ID: JavaGuide ),作者:guang19,授權(quán)轉(zhuǎn)載發(fā)布。

使用過簡書,知乎或 b 站的小伙伴應(yīng)該都有這樣的使用體驗(yàn):當(dāng)有其他用戶關(guān)注我們或者私信我們的行為時(shí),我們會(huì)收到相關(guān)的消息。 雖然這些功能看上去簡單,但其背后的設(shè)計(jì)是非常復(fù)雜的,幾乎是一個(gè)完成的系統(tǒng),可以稱之為 站內(nèi)消息系統(tǒng)

我以 b 站舉例(個(gè)人認(rèn)為 b 站的消息系統(tǒng)是我見過的非常完美的,UI 也最為人性化的):

b站站內(nèi)消息

可以看到 b 站把消息大致分為了三類:

  1. 系統(tǒng)推送的通知(System Notice);

  2. 回復(fù)、@、點(diǎn)贊等用戶行為產(chǎn)生的提醒(Remind);

  3. 用戶之間的私信(Chat)。

這樣設(shè)計(jì)不僅分類明確,且處于同一個(gè)主體的事件提醒還會(huì)做一個(gè)聚合,極大的提高了用戶體驗(yàn),不讓用戶收到太多分散的消息。

舉個(gè)例子:比如你在某個(gè)視頻或某篇文章下發(fā)表了評(píng)論,有 100 個(gè)人給你的評(píng)論點(diǎn)了贊,那么你希望消息頁面呈現(xiàn)的是一個(gè)一個(gè)用戶給你點(diǎn)贊的提醒,還是像以下聚合之后的提醒:

消息的聚合

我相信你大概率會(huì)選擇后者。

我認(rèn)為對(duì)于很多應(yīng)用來說,這樣的設(shè)計(jì)都是非常合理的,接下來我寫寫我對(duì)于消息系統(tǒng)的設(shè)計(jì)。

系統(tǒng)通知(System Notice)

系統(tǒng)通知一般是由后臺(tái)管理員發(fā)出,然后指定某一類(全體,個(gè)人等)用戶接收。基于此設(shè)想,可以把系統(tǒng)通知大致分為兩張表:

  1. t_manager_system_notice(管理員系統(tǒng)通知表) :記錄管理員發(fā)出的通知 ;

  2. t_user_system_notice(用戶系統(tǒng)通知表) : 存儲(chǔ)用戶接受的通知。

t_manager_system_notice 結(jié)構(gòu)如下:

字段名類型描述
system_notice_idLONG系統(tǒng)通知 ID
titleVARCHAR標(biāo)題
contentTEXT內(nèi)容
typeVARCHAR發(fā)給哪些用戶:單用戶 single;全體用戶 all,vip 用戶,具體類型各位小伙伴可以根據(jù)自己的需求選擇
stateBOOLEAN是否已被拉取過,如果已經(jīng)拉取過,就無需再次拉取
recipient_idLONG接受通知的用戶的 ID,如果 type 為單用戶,那么 recipient 為該用戶的 ID;否則 recipient 為 0
manager_idLONG發(fā)布通知的管理員 ID
publish_timeTIMESTAMP發(fā)布時(shí)間

t_user_system_notice 結(jié)構(gòu)如下:

字段名類型描述
user_notice_idLONG主鍵 ID
stateBOOLEAN是否已讀
system_notice_idLONG系統(tǒng)通知的 ID
recipient_idLONG接受通知的用戶的 ID
pull_timeTIMESTAMP拉取通知的時(shí)間

當(dāng)管理員發(fā)布一條通知后,將通知插入 t_manager_system_notice 表中,然后系統(tǒng)定時(shí)的從 t_manager_system_notice 表中拉取通知,然后根據(jù)通知的 type 將通知插入 t_user_system_notice 表中。

如果通知的 type 是 single 的,那就只需要插入一條記錄到 t_user_system_notice 中。如果是全體用戶,那么就需要將一個(gè)通知批量根據(jù)不同的用戶 ID 插入到 t_user_system_notice 中,這個(gè)數(shù)據(jù)量就需要根據(jù)平臺(tái)的用戶量來計(jì)算。

舉個(gè)例子: 管理員 A 發(fā)布了一個(gè)活動(dòng)的通知,他需要將這個(gè)通知發(fā)布給全體用戶,當(dāng)拉取時(shí)間到來時(shí),系統(tǒng)會(huì)將這一條通知取出。隨后系統(tǒng)到用戶表中查詢選取所有用戶的 ID,然后將這一條通知的信息根據(jù)所有用戶的 ID,批量插入 t_user_system_notice 中。用戶需要查看系統(tǒng)通知時(shí),從 t_user_system_notice 表中查詢就行了。

注意:

  1. 因?yàn)橐淮卫〉臄?shù)據(jù)量可能很大,所以兩次拉取的時(shí)間間隔可以設(shè)置的長一些。

  2. 拉取 t_manager_system_notice 表中的通知時(shí),需要判斷 state,如果已經(jīng)拉取過,就不需要重復(fù)拉取, 否則會(huì)造成重復(fù)消費(fèi)。

  3. 當(dāng)一條通知需要發(fā)布給全體用戶時(shí),我們應(yīng)該考慮到用戶的活躍度。因?yàn)槿绻行┯脩糸L期不活躍, 我們還將通知推送給他(她),這顯然會(huì)造成空間的浪費(fèi)。 所以在選取用戶 ID 時(shí),我們可以將用戶上次 登錄的時(shí)間與推送時(shí)間做一個(gè)比較,如果用戶一年未登陸或幾個(gè)月未登錄,我們就不選取其 ID,進(jìn)而避免 無謂的推送。

  4. 有的小伙伴可能有疑問: 某條通知已經(jīng)被拉取過的話,在其后注冊(cè)的用戶是不是不能再接收到這條通知? 是的。但如果你想將已拉取過的通知推送給那些后注冊(cè)的用戶,也不是特別大的問題。 只需要再寫一個(gè)定時(shí)任務(wù),這個(gè)定時(shí)任務(wù)可以將通知的 push_time 與用戶的注冊(cè)時(shí)間比較一下,重新推送即可。

以上就是系統(tǒng)通知的設(shè)計(jì)了,接下來再看看較難的提醒類型的消息。

事件提醒(EventRemind)

之所以稱提醒類型的消息為事件提醒,是因?yàn)榇祟愊⒕峭ㄟ^用戶的行為產(chǎn)生的,如下:

  • xxx 在某個(gè)評(píng)論中@了你;

  • xxx 點(diǎn)贊了你的文章;

  • xxx 點(diǎn)贊了你的評(píng)論;

  • xxx 回復(fù)了你的文章;

  • xxx 回復(fù)了你的評(píng)論。

諸如此類事件,我們以單詞 action 形容不同的事件(點(diǎn)贊,回復(fù),at)。 可以看到除了事件之外,我們還需要了解用戶是在哪個(gè)地方產(chǎn)生的事件,以便當(dāng)我們收到提醒時(shí), 點(diǎn)擊這條消息就可以去到事件現(xiàn)場,從而增強(qiáng)用戶體驗(yàn),我以事件源 source 來形容事件發(fā)生的地方。

  • 當(dāng) action 為點(diǎn)贊,source 為文章時(shí),我就知道:有用戶點(diǎn)贊了我的某篇文章;

  • 當(dāng) action 為點(diǎn)贊,source 為評(píng)論時(shí),我就知道:有用戶點(diǎn)贊了我的某條評(píng)論;

  • 當(dāng) action 為@(at), source 為評(píng)論時(shí),我就知道:有用戶在某條評(píng)論里@了我;

  • 當(dāng) action 為回復(fù),source 為文章時(shí),我就知道:有用戶回復(fù)了我的某篇文章;

  • 當(dāng) action 為回復(fù),source 為評(píng)論時(shí),我就知道:有用戶回復(fù)了我的某條評(píng)論;

由此可以設(shè)計(jì)出事件提醒表 t_event_remind,其結(jié)構(gòu)如下:

字段名類型描述
event_remind_idLONG消息 ID
actionVARCHAR動(dòng)作類型,如點(diǎn)贊、at(@)、回復(fù)等
source_idLONG事件源 ID,如評(píng)論 ID、文章 ID 等
source_typeVARCHAR事件源類型:"Comment"、"Post"等
source_contentVARCHAR事件源的內(nèi)容,比如回復(fù)的內(nèi)容,回復(fù)的評(píng)論等等
urlVARCHAR事件所發(fā)生的地點(diǎn)鏈接 url
stateBOOLEAN是否已讀
sender_idLONG操作者的 ID,即誰關(guān)注了你,at 了你
recipient_idLONG接受通知的用戶的 ID
remind_timeTIMESTAMP提醒的時(shí)間

消息聚合

消息聚合只適用于事件提醒,以聚合之后的點(diǎn)贊消息來說:

  • 100 人 {點(diǎn)贊} 了你的 {文章 ID = 1} :《A》;

  • 100 人 {點(diǎn)贊} 了你的 {文章 ID = 2} :《B》;

  • 100 人 {點(diǎn)贊} 了你的 {評(píng)論 ID = 3} :《C》;

聚合之后的消息明顯有兩個(gè)特征,即:action 和 source type,這是系統(tǒng)消息和私信都不具備的, 所以我個(gè)人認(rèn)為事件提醒的設(shè)計(jì)要稍微比系統(tǒng)消息和私信復(fù)雜。

如何聚合?

稍稍觀察下聚合的消息就可以發(fā)現(xiàn):某一類的聚合消息之間是按照 source type 和 source id 來分組的, 因此我們可以得出以下偽 SQL:

SELECT * FROM t_event_remind WHERE recipient_id = 用戶ID

當(dāng)然,SQL 層面的結(jié)果集處理還是很麻煩的,所以我的想法先把用戶所有的點(diǎn)贊消息先查出來, 然后在程序里面進(jìn)行分組,這樣會(huì)簡單不少。

拓展

其實(shí)還有一種設(shè)計(jì)提醒表的做法,即按業(yè)務(wù)分類,不同的提醒存入不同的表,這樣可以分為:

  1. 點(diǎn)贊提醒表

  2. 回復(fù)提醒表

  3. at(@)提醒表。

我認(rèn)為這種設(shè)計(jì)比第一種的更松耦合,不必所有類型的提醒都擠在一張表里,但是這也會(huì)帶來表數(shù)量的膨脹。 所以各位小伙伴可以自行選擇方案。

私信

站內(nèi)私信一般都是點(diǎn)到點(diǎn)的,且要求是實(shí)時(shí)的,服務(wù)端可以采用 Netty 等高性能網(wǎng)絡(luò)通信框架完成請(qǐng)求。 我們還是以 b 站為例,看看它是怎么設(shè)計(jì)的:

站內(nèi)消息系統(tǒng)的設(shè)計(jì)

b 站的私信部分可以分為兩部分:

  1. 左邊的與不同用戶的聊天室;

  2. 與當(dāng)前正在對(duì)話的用戶的對(duì)話框,顯示了當(dāng)前用戶與目標(biāo)用戶的所有消息。

按照這個(gè)設(shè)計(jì),我們可以先設(shè)計(jì)出聊天室表 t_private_chat,因?yàn)槭且粚?duì)一,所以聊天室表會(huì)包含對(duì)話的兩個(gè)用戶的信息:

字段名類型描述
private_chat_idLONG聊天室 ID
user1_idLONG用戶 1 的 ID
user2_idLONG用戶 2 的 ID
last_messageVARCHAR最后一條消息的內(nèi)容

這里 user1_id 和 user2_id 代表兩個(gè)用戶的 ID,并無特定的先后順序。

接下來是私信表 t_private_message 了,私信自然和所屬的聊天室有聯(lián)系,且考慮到私信可以在記錄中刪除(刪除了只是不顯示記錄,但是對(duì)方會(huì)有記錄,撤回才是真正的刪除),就還需要記錄私信的狀態(tài),以下是我的設(shè)計(jì):

字段名類型描述
private_message_idLONG私信 ID
contentTEXT私信內(nèi)容
stateBOOLEAN是否已讀
sender_removeBOOLEAN發(fā)送消息的人是否把這條消息從聊天記錄中刪除了
recipient_removeBOOLEAN接受人是否把這條消息從聊天記錄刪除了
sender_idLONG發(fā)送者 ID
recipient_idLONG接受者 ID
send_timeTIMESTAMP發(fā)送時(shí)間

消息設(shè)置

消息設(shè)置一般都是針對(duì)提醒類型的消息的,且肯定是由用戶自己設(shè)置的。所以我想到一般有以下設(shè)置選項(xiàng):

  1. 是否開啟點(diǎn)贊提醒;

  2. 是否開啟回復(fù)提醒;

  3. 是否開啟@提醒;

下面是 b 站的消息設(shè)置:

消息設(shè)置

可以看到 b 站還添加了陌生人選項(xiàng),也就是說如果給你發(fā)送私信的用戶不是你關(guān)注的用戶,那么視之為陌生人私信,就不接受。

以下是我對(duì)于消息設(shè)置的設(shè)計(jì):

字段名類型描述
user_idLONG用戶 ID
like_messageBOOLEAN是否接收點(diǎn)贊消息
reply_messageBOOLEAN是否接收回復(fù)消息
at_messageBOOLEAN是否接收 at 消息
stranger_messageBOOLEAN是否接收陌生人的私信

總結(jié)

以上就是我對(duì)于整個(gè)站內(nèi)消息系統(tǒng)的大概設(shè)計(jì)了,我參考了很多文章的內(nèi)容以及很多網(wǎng)站的設(shè)計(jì),但實(shí)際項(xiàng)目的需求肯定與我所介紹的有很多出入,所以各位小伙伴可以酌情參考。

分享到:
標(biāo)簽:B站 系統(tǒng) 網(wǎng)站設(shè)計(jì)
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績?cè)u(píng)定