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

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


咨詢
建站咨詢
