新聞中心
?01 整體介紹
背景
這個(gè)項(xiàng)目誕生的背景和企業(yè)內(nèi)生的需求不太一樣,主要是某一天二哥說,“我們一起搞事吧”, 樓仔問,“搞什么”,然后這個(gè)項(xiàng)目的需求就來了

成都網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)公司!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、微信平臺小程序開發(fā)、集團(tuán)成都定制網(wǎng)站等服務(wù)項(xiàng)目。核心團(tuán)隊(duì)均擁有互聯(lián)網(wǎng)行業(yè)多年經(jīng)驗(yàn),服務(wù)眾多知名企業(yè)客戶;涵蓋的客戶類型包括:成都辦公空間設(shè)計(jì)等眾多領(lǐng)域,積累了大量豐富的經(jīng)驗(yàn),同時(shí)也獲得了客戶的一致表揚(yáng)!
言歸正傳,我們主要的目的是希望打造一個(gè)切實(shí)可用的項(xiàng)目,依托于這個(gè)項(xiàng)目,將java從業(yè)者所用到的技術(shù)棧真實(shí)的展現(xiàn)出來,對于經(jīng)驗(yàn)不是那么足的小伙伴,可以在一個(gè)真實(shí)的系統(tǒng)上,理解到自己學(xué)習(xí)的知識點(diǎn)是如何落地的,同時(shí)也能真實(shí)的了解一個(gè)項(xiàng)目是從0到1實(shí)現(xiàn)的全過程
系統(tǒng)模塊介紹
系統(tǒng)架構(gòu)
基于社區(qū)系統(tǒng)的分層特點(diǎn),將整個(gè)系統(tǒng)架構(gòu)劃分為展示層,應(yīng)用層,服務(wù)層,如下圖
展示層
其中展示層主要為用戶直接接觸的視圖層,基于用戶角色,分別提供為面向普通用戶的前臺與面向管理員的后臺
前臺web
- 采用Thymleaf模板引擎進(jìn)行視圖渲染
- 對于不關(guān)心前端技術(shù)棧的小伙伴相對友好,學(xué)習(xí)成本低,只用會基本的html,css,js即可
管理后臺
- 采用成熟的前后端分離技術(shù)方案
- 前端基于react成熟框架搭建
應(yīng)用層
應(yīng)用層,也可以稱為業(yè)務(wù)層,強(qiáng)業(yè)務(wù)相關(guān),其中每個(gè)劃分出來的模塊有較明顯的業(yè)務(wù)邊界,雖然在上圖中區(qū)分了前臺、后臺
但是需要注意的是,后臺也是同樣有文章、評論、用戶等業(yè)務(wù)功能的,前臺與后臺可使用應(yīng)用主要是權(quán)限粒度管理的差異性,對于技術(shù)派系統(tǒng)而言,我們的應(yīng)用可分為:
- 文章
- 專欄
- 評論
- 用戶
- 收藏
- 訂閱
- 運(yùn)營
- 審核
- 類目標(biāo)簽
- 統(tǒng)計(jì)
服務(wù)層
我們將一些通用的、可抽離業(yè)務(wù)屬性的功能模塊,沉淀到服務(wù)層,作為一個(gè)一個(gè)的基礎(chǔ)服務(wù)進(jìn)行設(shè)計(jì),比如計(jì)數(shù)服務(wù)、消息服務(wù)等,通常他們最大特點(diǎn)就是獨(dú)立與業(yè)務(wù)之外,適用性更廣,并不局限在特定的業(yè)務(wù)領(lǐng)域內(nèi),可以作為通用的技術(shù)方案存在
在技術(shù)派的項(xiàng)目設(shè)計(jì)中,我們擬定以下基礎(chǔ)服務(wù)
- 用戶權(quán)限管理 (auth)
- 消息中心 (mq)
- 計(jì)數(shù) (redis)
- 搜索服務(wù) (es)
- 推薦 (recommend)
- 監(jiān)控運(yùn)維 (prometheus)
平臺資源層
這一層可以理解為更基礎(chǔ)的下層支撐
- 服務(wù)資源:數(shù)據(jù)庫、redis、es、mq
- 硬件資源:容器,ecs服務(wù)器
術(shù)語介紹
技術(shù)派整個(gè)系統(tǒng)中涉及到的術(shù)語并不多,也很容易理解,下面針對幾個(gè)常用的進(jìn)行說明
- 用戶:特指通過微信公眾號掃碼注冊的用戶,可以發(fā)布文章、閱讀文章等
- 管理員:可以登錄后臺的特殊用戶
- 文章:即博文
- 專欄:由一系列相關(guān)的文章組成的一個(gè)合集
- 訂閱:專指關(guān)注用戶
02 系統(tǒng)模塊設(shè)計(jì)
針對前面技術(shù)派的業(yè)務(wù)架構(gòu)拆分,技術(shù)派的實(shí)際項(xiàng)目劃分,主要是五個(gè)模塊,相反并沒由將上面的每個(gè)應(yīng)用、服務(wù)抽離為獨(dú)立的模塊,主要是為了避免過渡設(shè)計(jì),粒度劃分太細(xì)會增加整個(gè)項(xiàng)目的理解維護(hù)成本
這里設(shè)置五個(gè)相對獨(dú)立的模塊,則主要是基于邊界特別清晰這一思考點(diǎn)進(jìn)行,后續(xù)做微服務(wù)演進(jìn)時(shí),下面每個(gè)模塊可以作為獨(dú)立的微服務(wù)存在
用戶模塊
在技術(shù)派中,整個(gè)用戶模塊從功能角度可以分為
- 注冊登錄
- 權(quán)限管理(是的,權(quán)限管理也放在這里了)
- 業(yè)務(wù)邏輯
注冊登錄
方案設(shè)計(jì)
注冊登錄除了常見的用戶名+密碼的登錄方式之外,現(xiàn)在也有流行的手機(jī)號+驗(yàn)證,第三方授權(quán)登錄;我們最終選擇微信公眾號登錄方式(其最主要的目的,相信大家也知道...)
對于個(gè)人公眾號,很多權(quán)限沒有;因此這個(gè)登錄的具體實(shí)現(xiàn),有兩種實(shí)現(xiàn)策略
- 點(diǎn)擊登錄,登錄頁顯示二維碼 + 輸入框 -> 用戶關(guān)注公眾號,輸入 "login" 獲取登錄驗(yàn)證碼 -> 在登錄界面輸入驗(yàn)證碼實(shí)現(xiàn)登錄
- 點(diǎn)擊登錄,登錄頁顯示二維碼 + 驗(yàn)證碼 -> 用戶關(guān)注公眾號,將登錄頁面上的驗(yàn)證碼輸入到微信公眾號 -> 自動登錄
其中第一種策略,類似于手機(jī)號/驗(yàn)證碼的登錄方式,主要是根據(jù)系統(tǒng)返回的驗(yàn)證碼來主動登錄
優(yōu)點(diǎn):
- 代碼實(shí)現(xiàn)簡單,邏輯清晰
缺點(diǎn):
- 操作流程復(fù)雜,用戶需要輸入兩次
對于第二種策略,如果是企業(yè)公眾號,是可以省略輸入驗(yàn)證碼這一步驟的,借助動態(tài)二維碼來直接實(shí)現(xiàn)掃碼登錄;對于我們這種個(gè)人公眾號,則需要多來一步,通過輸入驗(yàn)證碼來將微信公眾號的用戶與需要登錄的用戶綁定起來
登錄工作流程如下:
庫表設(shè)計(jì)
基于公眾號的登錄方式,看一下用戶登錄表的設(shè)計(jì)
CREATE TABLE `user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`third_account_id` varchar(128) NOT NULL DEFAULT '' COMMENT '第三方用戶ID',
`user_name` varchar(64) NOT NULL DEFAULT '' COMMENT '用戶名',
`password` varchar(128) NOT NULL DEFAULT '' COMMENT '密碼',
`login_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '登錄方式: 0-微信登錄,1-賬號密碼登錄',
`deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新時(shí)間',
PRIMARY KEY (`id`),
KEY `key_third_account_id` (`third_account_id`),
KEY `key_user_name` (`user_name`),
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用戶登錄表';
注意上面的表結(jié)構(gòu)設(shè)計(jì),我們?nèi)哂嗔?nbsp;user_name?, password 用戶名密碼的登錄方式,主要是給管理員登錄后臺使用
用戶首次登錄之后,會在user表中插入一條數(shù)據(jù),主要關(guān)注 third_account_id 這個(gè)字段,它記錄的是微信開放平臺返回的唯一用戶id
權(quán)限管理
權(quán)限管理會分為兩塊:用戶身份識別 + 鑒權(quán)
方案設(shè)計(jì)
用戶身份識別:
現(xiàn)在用戶的身份識別有非常多的方案,我們現(xiàn)在采用的是最基礎(chǔ)、歷史最悠久的方案,cookie + session 方式(后續(xù)會迭代為分布式session + jwt)
整體流程:
- 用戶登錄成功,服務(wù)器生成sessionId -> userId 映射關(guān)系
- 服務(wù)器返回sessionId,寫到客戶端的瀏覽器cookie
- 后續(xù)用戶請求,攜帶cookie
- 服務(wù)器從cookie中獲取sessionId,然后找到uesrId
服務(wù)內(nèi)部身份傳遞:
另外一個(gè)需要考慮的點(diǎn)則是用戶的身份如何在整個(gè)系統(tǒng)內(nèi)傳遞? 對于一期我們采用的單體架構(gòu)而言,借助ThreadLocal來實(shí)現(xiàn)
- 自定義Filter,實(shí)現(xiàn)用戶身份識別(即上面的流程,從cookie中拿到SessionId,轉(zhuǎn)userId)
- 定義全局上下文ReqInfoContext:將用戶信息,寫入全局共享的ThreadLocal中
- 在系統(tǒng)內(nèi),需要獲取當(dāng)前用戶的地方,直接通過訪問 ReqInfoContext上下文獲取用戶信息
- 請求返回前,銷毀上下文中當(dāng)前登錄用戶信息
鑒權(quán)
根據(jù)用戶角色與接口權(quán)限要求進(jìn)行判定,我們設(shè)計(jì)三種權(quán)限點(diǎn)類型
- ADMIN:只有管理員才能訪問的接口
- LOGIN:只有登錄了才能訪問的接口
- ALL:默認(rèn),沒有權(quán)限限制
我們在需要權(quán)限判定的接口上,添加上對應(yīng)的權(quán)限要求,然后借助AOP來實(shí)現(xiàn)權(quán)限判斷
- 當(dāng)接口上有權(quán)限點(diǎn)要求時(shí)(除ALL之外)
- 首先獲取用戶信息,如果沒有登錄,則直接報(bào)403
- 對于ADMIN限制的接口,要求查看用戶角色,必須為admin
庫表設(shè)計(jì)
我們將用戶角色信息寫入用戶基本信息表中,沒有單獨(dú)抽出一個(gè)角色表,然后進(jìn)行映射,主要是因?yàn)檫@個(gè)系統(tǒng)邏輯相對清晰,沒有太復(fù)雜的角色關(guān)系,因此采用了輕量級的設(shè)計(jì)方案
-- pai_coding.user_info definition
CREATE TABLE `user_info` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '用戶ID',
`user_name` varchar(50) NOT NULL DEFAULT '' COMMENT '用戶名',
`photo` varchar(128) NOT NULL DEFAULT '' COMMENT '用戶圖像',
`position` varchar(50) NOT NULL DEFAULT '' COMMENT '職位',
`company` varchar(50) NOT NULL DEFAULT '' COMMENT '公司',
`profile` varchar(225) NOT NULL DEFAULT '' COMMENT '個(gè)人簡介',
`user_role` int(4) NOT NULL DEFAULT '0' COMMENT '0 普通用戶 1 超管',
`extend` varchar(1024) NOT NULL DEFAULT '' COMMENT '擴(kuò)展字段',
`ip` json NOT NULL COMMENT '用戶的ip信息',
`deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新時(shí)間',
PRIMARY KEY (`id`),
KEY `key_user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用戶個(gè)人信息表';
業(yè)務(wù)邏輯
在業(yè)務(wù)模塊,主要說兩塊,一個(gè)是用戶的軌跡,一個(gè)是訂閱關(guān)注
訂閱關(guān)注
訂閱關(guān)注這塊業(yè)務(wù)主要是用戶可以相互關(guān)注,核心點(diǎn)就在于維護(hù)用戶與用戶之間的訂閱關(guān)系
業(yè)務(wù)邏輯上沒有太復(fù)雜的東西,核心就是需要一張表來記錄關(guān)注與被關(guān)注情況
-- pai_coding.user_relation definition
CREATE TABLE `user_relation` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '作者用戶ID',
`follow_user_id` int(10) unsigned NOT NULL COMMENT '關(guān)注userId的用戶id,即粉絲userId',
`follow_state` tinyint(2) unsigned NOT NULL DEFAULT '0' COMMENT '閱讀狀態(tài): 0-未關(guān)注,1-已關(guān)注,2-取消關(guān)注',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新時(shí)間',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_follow` (`user_id`,`follow_user_id`),
KEY `key_follow_user_id` (`follow_user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用戶關(guān)系表';
用戶軌跡
在技術(shù)派的整體設(shè)計(jì)中,我們希望記錄用戶的閱讀歷史、關(guān)注列表、收藏列表、評價(jià)的文章列表,對于這種用戶行為軌跡的訴求,我們采用設(shè)計(jì)一張大寬表的策略,其主要目的在于
- 記錄用戶的關(guān)鍵動作
- 便于文章的相關(guān)計(jì)數(shù)
接下來看一下表結(jié)構(gòu)設(shè)計(jì)
-- pai_coding.user_foot definition
CREATE TABLE `user_foot` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '用戶ID',
`document_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '文檔ID(文章/評論)',
`document_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '文檔類型:1-文章,2-評論',
`document_user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '發(fā)布該文檔的用戶ID',
`collection_stat` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '收藏狀態(tài): 0-未收藏,1-已收藏,2-取消收藏',
`read_stat` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '閱讀狀態(tài): 0-未讀,1-已讀',
`comment_stat` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '評論狀態(tài): 0-未評論,1-已評論,2-刪除評論',
`praise_stat` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '點(diǎn)贊狀態(tài): 0-未點(diǎn)贊,1-已點(diǎn)贊,2-取消點(diǎn)贊',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新時(shí)間',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_user_doucument` (`user_id`,`document_id`,`document_type`),
KEY `idx_doucument_id` (`document_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用戶足跡表';
我們將用戶 + 文章設(shè)計(jì)唯一鍵,用來記錄用戶對自己閱讀過的文章的行為,因此可以直接通過這個(gè)表獲取用戶的歷史軌跡
同時(shí)也可以從文章的角度出發(fā),查看被哪些用戶點(diǎn)贊、收藏過
小結(jié)
用戶模塊的核心支撐在上面幾塊,請重點(diǎn)關(guān)注上面的示意圖與表結(jié)構(gòu);當(dāng)然用戶的功能點(diǎn)不止于上面幾個(gè),比如基礎(chǔ)的個(gè)人主頁、用戶信息等也屬于用戶模塊的業(yè)務(wù)范疇
文章模塊
我們將文章和專欄都放在一起,同樣也將類目管理、標(biāo)簽管理等也都放在這個(gè)模塊中,實(shí)際上若文章模塊過于龐大,也是可以按照最開始的劃分進(jìn)行繼續(xù)拆分的;這里放在一起的主要原因在于他們都是圍繞基本的文章這一業(yè)務(wù)屬性來的,可以聚合在一起
文章
文章的核心就在于發(fā)布、查看
基本的發(fā)布流程:
- 用戶登錄,進(jìn)入發(fā)布頁面
- 輸入標(biāo)題、文章
- 選擇分類、標(biāo)簽,封面、簡介
- 提交文章,進(jìn)入待審核狀態(tài),僅用戶可看詳情
- 管理員審核通過,所有人可看詳情
文章庫表設(shè)計(jì)
考慮到文章的內(nèi)容通常較大,在很多的業(yè)務(wù)場景中,我們實(shí)際上是不需要文章內(nèi)容的,如首頁、推薦列表等都只需要文章的標(biāo)題等信息;此外我們也希望對文章做一個(gè)版本管理(比如上線之后,再修改則新生成一個(gè)版本)
因此我們對文章設(shè)計(jì)了兩張表
-- pai_coding.article definition
CREATE TABLE `article` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '用戶ID',
`article_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '文章類型:1-博文,2-問答',
`title` varchar(120) NOT NULL DEFAULT '' COMMENT '文章標(biāo)題',
`short_title` varchar(120) NOT NULL DEFAULT '' COMMENT '短標(biāo)題',
`picture` varchar(128) NOT NULL DEFAULT '' COMMENT '文章頭圖',
`summary` varchar(300) NOT NULL DEFAULT '' COMMENT '文章摘要',
`category_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '類目ID',
`source` tinyint(4) NOT NULL DEFAULT '1' COMMENT '來源:1-轉(zhuǎn)載,2-原創(chuàng),3-翻譯',
`source_url` varchar(128) NOT NULL DEFAULT '1' COMMENT '原文鏈接',
`offical_stat` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '官方狀態(tài):0-非官方,1-官方',
`topping_stat` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '置頂狀態(tài):0-不置頂,1-置頂',
`cream_stat` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '加精狀態(tài):0-不加精,1-加精',
`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '狀態(tài):0-未發(fā)布,1-已發(fā)布',
`deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新時(shí)間',
PRIMARY KEY (`id`),
KEY `idx_category_id` (`category_id`),
KEY `idx_title` (`title`),
KEY `idx_short_title` (`short_title`)
) ENGINE=InnoDB AUTO_INCREMENT=173 DEFAULT CHARSET=utf8mb4 COMMENT='文章表';
-- pai_coding.article_detail definition
CREATE TABLE `article_detail` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`article_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '文章ID',
`version` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '版本號',
`content` longtext COMMENT '文章內(nèi)容',
`deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新時(shí)間',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_article_version` (`article_id`,`version`)
) ENGINE=InnoDB AUTO_INCREMENT=141 DEFAULT CHARSET=utf8mb4 COMMENT='文章詳情表';
文章對應(yīng)的分類,我們要求一個(gè)文章只能掛在一個(gè)分類下
-- pai_coding.category definition
CREATE TABLE `category` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`category_name` varchar(64) NOT NULL DEFAULT '' COMMENT '類目名稱',
`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '狀態(tài):0-未發(fā)布,1-已發(fā)布',
`rank` tinyint(4) NOT NULL DEFAULT '0' COMMENT '排序',
`deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新時(shí)間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COMMENT='類目管理表';
文章對應(yīng)的標(biāo)簽屬性,一個(gè)文章可以有多個(gè)標(biāo)簽
-- pai_coding.tag definition
CREATE TABLE `tag` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`tag_name` varchar(120) NOT NULL COMMENT '標(biāo)簽名稱',
`tag_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '標(biāo)簽類型:1-系統(tǒng)標(biāo)簽,2-自定義標(biāo)簽',
`category_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '類目ID',
`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '狀態(tài):0-未發(fā)布,1-已發(fā)布',
`deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新時(shí)間',
PRIMARY KEY (`id`),
KEY `idx_category_id` (`category_id`)
) ENGINE=InnoDB AUTO_INCREMENT=147 DEFAULT CHARSET=utf8mb4 COMMENT='標(biāo)簽管理表';
-- pai_coding.article_tag definition
CREATE TABLE `article_tag` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`article_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '文章ID',
`tag_id` int(11) NOT NULL DEFAULT '0' COMMENT '標(biāo)簽',
`deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新時(shí)間',
PRIMARY KEY (`id`),
KEY `idx_tag_id` (`tag_id`)
) ENGINE=InnoDB AUTO_INCREMENT=145 DEFAULT CHARSET=utf8mb4 COMMENT='文章標(biāo)簽映射';
專欄
專欄主要是一系列文章的合集,基于此最簡單的設(shè)計(jì)方案就是加一個(gè)專欄表,然后再加一個(gè)專欄與文章的映射表
但是需要注意的是專欄中文章的順序,支持調(diào)整
專欄庫表設(shè)計(jì)
專欄表
-- pai_coding.column_info definition
CREATE TABLE `column_info` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '專欄ID',
`column_name` varchar(64) NOT NULL DEFAULT '' COMMENT '專欄名',
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '作者id',
`introduction` varchar(256) NOT NULL DEFAULT '' COMMENT '專欄簡述',
`cover` varchar(128) NOT NULL DEFAULT '' COMMENT '專欄封面',
`state` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '狀態(tài): 0-審核中,1-連載,2-完結(jié)',
`publish_time` timestamp NOT NULL DEFAULT '1970-01-02 00:00:00' COMMENT '上線時(shí)間',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新時(shí)間',
`section` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '排序',
`nums` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '專欄預(yù)計(jì)的更新的文章數(shù)',
`type` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '專欄類型 0-免費(fèi) 1-登錄閱讀 2-限時(shí)免費(fèi)',
`free_start_time` timestamp NOT NULL DEFAULT '1970-01-02 00:00:00' COMMENT '限時(shí)免費(fèi)開始時(shí)間',
`free_end_time` timestamp NOT NULL DEFAULT '1970-01-02 00:00:00' COMMENT '限時(shí)免費(fèi)結(jié)束時(shí)間',
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='專欄';
專欄文章表
-- pai_coding.column_article definition
CREATE TABLE `column_article` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`column_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '專欄ID',
`article_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '文章ID',
`section` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '章節(jié)順序,越小越靠前',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新時(shí)間',
PRIMARY KEY (`id`),
KEY `idx_column_id` (`column_id`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8mb4 COMMENT='專欄文章列表';
點(diǎn)贊收藏
再技術(shù)派中,對于文章提供了點(diǎn)贊、收藏、評論三種交互,這里重點(diǎn)看一下點(diǎn)贊與收藏;
實(shí)際上就是用戶與文章之間的操作行為,再前面的user_foot表就已經(jīng)介紹具體的表結(jié)構(gòu), 文章的統(tǒng)計(jì)計(jì)數(shù)就是根據(jù)這個(gè)表數(shù)據(jù)來的,當(dāng)前用戶與文章的點(diǎn)贊、收藏關(guān)系,同樣是根據(jù)這個(gè)表來的
唯一需要注意的點(diǎn),就是這個(gè)數(shù)據(jù)的插入、更新策略:
- 首次閱讀文章時(shí):插入一條數(shù)據(jù)
- 點(diǎn)贊:若記錄存在,則更新狀態(tài),之前時(shí)點(diǎn)贊的,設(shè)置為取消點(diǎn)贊;若記錄不存在,則插入一條點(diǎn)贊的記錄
- 收藏:同上
評論模塊
評論可以是針對文章進(jìn)行,也可以是針對另外一個(gè)評論進(jìn)行回復(fù),我們將回復(fù)也當(dāng)作是一個(gè)評論
評論
我們將評論和回復(fù)都當(dāng)成普通的評論,只是主體不同而已,因此一篇文章的評論列表,我們需要重點(diǎn)關(guān)注的就是,如何構(gòu)建評論與其回復(fù)之間的層級關(guān)系
對于這種評論與回復(fù)的層級關(guān)系,可以是建輔助表來處理;也可以是表內(nèi)的父子關(guān)系來處理,這里我們采用第二種策略
- 每個(gè)評論記錄它的上一級評論id(若只是針對文章的評論,那么上一級評論id = 0)
- 我們通過父子關(guān)系,在業(yè)務(wù)層進(jìn)行邏輯還原
庫表設(shè)計(jì)
針對上面的策略,核心的評論庫表設(shè)計(jì)如下
-- pai_coding.comment definition
CREATE TABLE `comment` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`article_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '文章ID',
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '用戶ID',
`content` varchar(300) NOT NULL DEFAULT '' COMMENT '評論內(nèi)容',
`top_comment_id` int(11) NOT NULL DEFAULT '0' COMMENT '頂級評論ID',
`parent_comment_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父評論ID',
`deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新時(shí)間',
PRIMARY KEY (`id`),
KEY `idx_article_id` (`article_id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=75 DEFAULT CHARSET=utf8mb4 COMMENT='評論表';
注意:
- 為什么再表中需要冗余一個(gè)頂級評論id ?
- 主要的目的是簡化業(yè)務(wù)層評論關(guān)系還原的復(fù)雜性
通過上面的表結(jié)構(gòu),關(guān)系還原的策略:
- 先查出文章的頂級評論(parent_comment_id = 0)
- 接下來就是針對每個(gè)頂級評論,查詢它下面的所有回復(fù) ( top_comment_id = comment_id)
- 構(gòu)建頂級評論下的回復(fù)父子關(guān)系(根據(jù)parent_comment_id來構(gòu)建依賴關(guān)系)
拓展:如果不存在top_comment_id,那么要實(shí)現(xiàn)上面這個(gè)還原,要怎么做呢?
評論點(diǎn)贊
技術(shù)派中同樣支持對評論進(jìn)行點(diǎn)贊,取消點(diǎn)贊;對于點(diǎn)贊的整體業(yè)務(wù)邏輯操作,實(shí)際上與文章的點(diǎn)贊一致,因此我們直接復(fù)用了文章的點(diǎn)贊邏輯,借助 user_foot 來實(shí)現(xiàn)的
說明
- 上面這種實(shí)現(xiàn)并不是一種優(yōu)雅的選擇,從user_foot的設(shè)計(jì)也能看出,它實(shí)際上與評論點(diǎn)贊這個(gè)業(yè)務(wù)是有些隔離的
- 采用上面這個(gè)方案的主要原因在于,點(diǎn)贊這種屬于通用的服務(wù),使用mysql來維系點(diǎn)贊與否以及計(jì)數(shù)統(tǒng)計(jì),再數(shù)據(jù)量大了之后,基本上玩不轉(zhuǎn);后續(xù)會介紹如何設(shè)計(jì)一個(gè)通用的點(diǎn)贊服務(wù),以此來替換技術(shù)派中當(dāng)前的點(diǎn)贊實(shí)現(xiàn)
- 這種設(shè)計(jì)思路也經(jīng)常體現(xiàn)在一個(gè)全新項(xiàng)目的設(shè)計(jì)中,最開始的設(shè)計(jì)并不會想著一蹴而就,整一個(gè)非常完美的系統(tǒng)出來,我們需要的是在最開始搭好基座、方便后續(xù)擴(kuò)展;另外一點(diǎn)就是,如何在當(dāng)前系統(tǒng)的基礎(chǔ)上,最小成本的支持業(yè)務(wù)需求(相信各位小伙伴在日常工作中,這些事情不會陌生)
消息模塊
消息模塊主要是記錄一些定義的事件,用于同步給用戶;我們整體采用Event/Listener的異步方案來進(jìn)行
在單機(jī)應(yīng)用中,借助Spring Event/Listener機(jī)制來實(shí)現(xiàn);在集群中,將借助MQ消息中間件來實(shí)現(xiàn)
消息通知
我們主要定義以下五種消息類型
- 評論
- 點(diǎn)贊
- 收藏
- 關(guān)注
- 系統(tǒng)消息
當(dāng)發(fā)生方面的行為之后,再相應(yīng)的地方進(jìn)行主動埋點(diǎn),手動發(fā)送一個(gè)消息事件,然后異步消費(fèi)事件,生成消息通知
需要注意一點(diǎn):
- 當(dāng)用戶點(diǎn)贊了一個(gè)文章,產(chǎn)生一個(gè)點(diǎn)贊消息之后;又取消了點(diǎn)贊,這個(gè)消息會怎樣?
- 撤銷還是依然保留?(技術(shù)派中選擇的方案是撤銷)
庫表設(shè)計(jì)
-- pai_coding.notify_msg definition
CREATE TABLE `notify_msg` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`related_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '關(guān)聯(lián)的主鍵',
`notify_user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '通知的用戶id',
`operate_user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '觸發(fā)這個(gè)通知的用戶id',
`msg` varchar(1024) NOT NULL DEFAULT '' COMMENT '消息內(nèi)容',
`type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '類型: 0-默認(rèn),1-評論,2-回復(fù) 3-點(diǎn)贊 4-收藏 5-關(guān)注 6-系統(tǒng)',
`state` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '閱讀狀態(tài): 0-未讀,1-已讀',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`update_time` timestamp NOT NULL DEFAULT CURRENT
分享標(biāo)題:對標(biāo)大廠的技術(shù)派詳細(xì)方案設(shè)計(jì)
本文來源:http://m.5511xx.com/article/dpdigjo.html


咨詢
建站咨詢
