備戰春招!開源社群系統 Echo 超全文件助力面試

飛天小牛肉發表於2021-02-21

 

博主東南大學碩士在讀,寒假前半個月到現在差不多一個多月,斷斷續續做完了這個專案,現在終於可以開源出來了,我的想法是為這個專案編寫一套完整的教程,包括技術選型分析、架構分析、業務邏輯分析、核心技術點分析、常見面試題等。不過說實話,這裡面涉及的一些技術我仍然停留在僅僅是會用的階段,當然,後面我會不斷學習,瞭解透徹這些技術的底層原理,不斷完善這套教程。

? 專案簡介

Echo 是一套前後端不分離的開源社群系統,基於目前主流 Java Web 技術棧(SpringBoot + MyBatis + MySQL + Redis + Kafka + Elasticsearch + Spring Security + ...),並提供詳細的開發文件和配套教程。包含帖子、評論、私信、系統通知、點贊、關注、搜尋、使用者設定、資料統計等模組。

原始碼連結:已託管在 Github 和 Gitee:

線上體驗:專案已經部署到騰訊雲伺服器,各位小夥伴們可直接線上體驗:http://1.15.127.74/。已內建三種不同身份的使用者:

 usernamepassword特殊許可權
管理員 admin admin 資料統計、刪除帖子
版主 master master 置頂帖子、加精帖子
普通使用者 user user  

文件地址:文件通過 Docsify + Gitee Pages 生成,國內訪問速度較快,線上訪問地址:https://veal98.gitee.io/echo

? 核心技術棧

後端:

  • Spring

  • Spring Boot 2.1.5 RELEASE

  • Spring MVC

  • ORM:MyBatis

  • 資料庫:MySQL 5.7

  • 分散式快取:Redis

  • 本地快取:Caffeine

  • 訊息佇列:Kafka 2.13-2.7.0

  • 搜尋引擎:Elasticsearch 6.4.3

  • 安全:Spring Security

  • 郵件任務:Spring Mail

  • 分散式定時任務:Spring Quartz

  • 日誌:SLF4J(日誌介面) + Logback(日誌實現)

前端:

  • Thymeleaf

  • Bootstrap 4.x

  • Jquery

  • Ajax

? 開發環境

  • 作業系統:Windows 10

  • 構建工具:Apache Maven

  • 整合開發工具:Intellij IDEA

  • 應用伺服器:Apache Tomcat

  • 介面測試工具:Postman

  • 壓力測試工具:Apache JMeter

  • 版本控制工具:Git

  • Java 版本:8

? 介面展示

首頁:

備戰春招!開源社群系統 Echo 超全文件助力面試

登入頁:

備戰春招!開源社群系統 Echo 超全文件助力面試

帖子詳情頁:

備戰春招!開源社群系統 Echo 超全文件助力面試

個人主頁:

備戰春招!開源社群系統 Echo 超全文件助力面試

朋友私信頁:

備戰春招!開源社群系統 Echo 超全文件助力面試

私信詳情頁:

備戰春招!開源社群系統 Echo 超全文件助力面試

系統通知頁:

備戰春招!開源社群系統 Echo 超全文件助力面試

通知詳情頁:

備戰春招!開源社群系統 Echo 超全文件助力面試

賬號設定頁:

備戰春招!開源社群系統 Echo 超全文件助力面試

資料統計頁:

備戰春招!開源社群系統 Echo 超全文件助力面試

搜尋詳情頁:

備戰春招!開源社群系統 Echo 超全文件助力面試

? 功能列表

備戰春招!開源社群系統 Echo 超全文件助力面試

  • 註冊
    • 使用者註冊成功,將使用者資訊存入 MySQL,但此時該使用者狀態為未啟用

    • 向使用者傳送啟用郵件,使用者點選連結則啟用賬號(Spring Mail)

  • 登入 | 登出
    • 進入登入介面,動態生成驗證碼,並將驗證碼短暫存入 Redis(60 秒)

    • 使用者登入成功(驗證使用者名稱、密碼、驗證碼),生成登入憑證且設定狀態為有效,並將登入憑證存入 Redis 注意:登入憑證存在有效期,在所有的請求執行之前,都會檢查憑證是否有效和是否過期,只要該使用者的憑證有效並在有效期時間內,本次請求就會一直持有該使用者資訊(使用 ThreadLocal 持有使用者資訊)

    • 勾選記住我,則延長登入憑證有效時間

    • 使用者登入成功,將使用者資訊短暫存入 Redis(1 小時)

    • 使用者登出,將憑證狀態設為無效,並更新 Redis 中該使用者的登入憑證資訊

  • 賬號設定
    • 修改頭像

      • 將使用者選擇的頭像圖片檔案上傳至七牛雲伺服器

    • 修改密碼

  • 帖子模組
    • 釋出帖子(過濾敏感詞),將其存入 MySQL

    • 分頁顯示所有的帖子

      • 支援按照 “發帖時間” 顯示

      • 支援按照 “熱度排行” 顯示(Spring Quartz)

    • 檢視帖子詳情

    • 許可權管理(Spring Security + Thymeleaf Security)

      • 未登入使用者無法發帖

      • “版主” 可以看到帖子的置頂和加精按鈕並執行相應操作

      • “管理員” 可以看到帖子的刪除按鈕並執行相應操作

      • “普通使用者” 無法看到帖子的置頂、加精、刪除按鈕,也無法執行相應操作

  • 評論模組
    • 釋出對帖子的評論(過濾敏感詞),將其存入 MySQL

    • 分頁顯示評論

    • 釋出對評論的回覆(過濾敏感詞)

    • 許可權管理(Spring Security)

      • 未登入使用者無法使用評論功能

  • 私信模組
    • 傳送私信(過濾敏感詞)

    • 私信列表

      • 查詢當前使用者的會話列表

      • 每個會話只顯示一條最新的私信

      • 支援分頁顯示

    • 私信詳情

      • 查詢某個會話所包含的所有私信

      • 訪問私信詳情時,將顯示的私信設為已讀狀態

      • 支援分頁顯示

    • 許可權管理(Spring Security)

      • 未登入使用者無法使用私信功能

  • 統一處理 404 / 500 異常
    • 普通請求異常

    • 非同步請求異常

  • 統一記錄日誌
  • 點贊模組
    • 支援對帖子、評論/回覆點贊

    • 第 1 次點贊,第 2 次取消點贊

    • 首頁統計帖子的點贊數量

    • 詳情頁統計帖子和評論/回覆的點贊數量

    • 詳情頁顯示當前登入使用者的點贊狀態(贊過了則顯示已贊)

    • 統計我的獲贊數量

    • 許可權管理(Spring Security)

      • 未登入使用者無法使用點贊相關功能

  • 關注模組
    • 關注功能

    • 取消關注功能

    • 統計使用者的關注數和粉絲數

    • 我的關注列表(查詢某個使用者關注的人),支援分頁

    • 我的粉絲列表(查詢某個使用者的粉絲),支援分頁

    • 許可權管理(Spring Security)

      • 未登入使用者無法使用關注相關功能

  • 系統通知模組
    • 通知列表

      • 顯示評論、點贊、關注三種型別的通知

    • 通知詳情

      • 分頁顯示某一類主題所包含的通知

      • 進入某種型別的系統通知詳情,則將該頁的所有未讀的系統通知狀態設定為已讀

    • 未讀數量

      • 分別顯示每種型別的系統通知的未讀數量

      • 顯示所有系統通知的未讀數量

    • 導航欄顯示所有訊息的未讀數量(未讀私信 + 未讀系統通知)

    • 許可權管理(Spring Security)

      • 未登入使用者無法使用系統通知功能

  • 搜尋模組
    • 釋出事件

      • 釋出帖子時,通過訊息佇列將帖子非同步地提交到 Elasticsearch 伺服器

      • 為帖子增加評論時,通過訊息佇列將帖子非同步地提交到 Elasticsearch 伺服器

    • 搜尋服務

      • 從 Elasticsearch 伺服器搜尋帖子

      • 從 Elasticsearch 伺服器刪除帖子(當帖子從資料庫中被刪除時)

    • 顯示搜尋結果

  • 網站資料統計(管理員專屬)
    • 獨立訪客 UV

      • 存入 Redis 的 HyperLogLog

      • 支援單日查詢和區間日期查詢

    • 日活躍使用者 DAU

      • 存入 Redis 的 Bitmap

      • 支援單日查詢和區間日期查詢

    • 許可權管理(Spring Security)

      • 只有管理員可以檢視網站資料統計

  • 優化網站效能
    • 使用本地快取 Caffeine 快取熱帖列表以及所有使用者帖子的總數

? 快速開始

各位如果需要將專案部署在本地進行測試,以下環境請提前備好:

  • Java 8

  • MySQL 5.7

  • Redis

  • Kafka 2.13-2.7.0

  • Elasticsearch 6.4.3

然後修改配置檔案中的資訊為你自己的本地環境,直接執行是執行不了的,而且相關私密資訊我全部用 xxxxxxx 代替了。

本地執行需要修改的配置檔案資訊如下:

1)application-develop.properties

  • MySQL

  • Spring Mail(郵箱需要開啟 SMTP 服務)

  • Kafka:consumer.group-id(該欄位見 Kafka 安裝包中的 consumer.proerties,可自行修改, 修改完畢後需要重啟 Kafka)

  • Elasticsearch:cluster-name(該欄位見 Elasticsearch 安裝包中的 elasticsearch.yml,可自行修改)

  • 七牛雲(需要新建一個七牛雲的物件儲存空間,用來存放上傳的頭像圖片)

2)logback-spring-develop.xml

  • LOG_PATH:日誌存放的位置

每次執行需要開啟:

  • MySQL

  • Redis

  • Elasticsearch

  • Kafka

另外,還需要事件建好資料庫 greatecommunity,然後依次執行專案 sql 資料夾下的這幾個 sql 檔案建立資料庫表:

備戰春招!開源社群系統 Echo 超全文件助力面試

? 資料庫設計

使用者 user

DROP TABLE IF EXISTS `user`;
SET character_set_client = utf8mb4 ;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
`password` varchar(50) DEFAULT NULL,
`salt` varchar(50) DEFAULT NULL,
`email` varchar(100) DEFAULT NULL,
`type` int(11) DEFAULT NULL COMMENT '0-普通使用者; 1-超級管理員; 2-版主;',
`status` int(11) DEFAULT NULL COMMENT '0-未啟用; 1-已啟用;',
`activation_code` varchar(100) DEFAULT NULL,
`header_url` varchar(200) DEFAULT NULL,
`create_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_username` (`username`(20)),
KEY `index_email` (`email`(20))
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;

討論帖 discuss_post

DROP TABLE IF EXISTS `discuss_post`;
SET character_set_client = utf8mb4 ;
CREATE TABLE `discuss_post` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`title` varchar(100) DEFAULT NULL,
`content` text,
`type` int(11) DEFAULT NULL COMMENT '0-普通; 1-置頂;',
`status` int(11) DEFAULT NULL COMMENT '0-正常; 1-精華; 2-拉黑;',
`create_time` timestamp NULL DEFAULT NULL,
`comment_count` int(11) DEFAULT NULL,
`score` double DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

評論(回覆)comment

CREATE TABLE `comment` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`entity_type` int(11) DEFAULT NULL COMMENT '評論目標的類別:1 帖子;2 評論 ',
`entity_id` int(11) DEFAULT NULL COMMENT '評論目標的 id',
`target_id` int(11) DEFAULT NULL COMMENT '指明對誰進行評論',
`content` text,
`status` int(11) DEFAULT NULL COMMENT '狀態:0 正常;1 禁用',
`create_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_user_id` (`user_id`),
KEY `index_entity_id` (`entity_id`)
) ENGINE=InnoDB AUTO_INCREMENT=247 DEFAULT CHARSET=utf8;

私信 message

DROP TABLE IF EXISTS `message`;
SET character_set_client = utf8mb4 ;
CREATE TABLE `message` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`from_id` int(11) DEFAULT NULL,
`to_id` int(11) DEFAULT NULL,
`conversation_id` varchar(45) NOT NULL,
`content` text,
`status` int(11) DEFAULT NULL COMMENT '0-未讀;1-已讀;2-刪除;',
`create_time` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_from_id` (`from_id`),
KEY `index_to_id` (`to_id`),
KEY `index_conversation_id` (`conversation_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

? 部署架構

我每個都只部署了一臺,以下是理想的部署架構:

備戰春招!開源社群系統 Echo 超全文件助力面試

? 功能邏輯圖

畫了一些不是那麼嚴謹的圖幫助各位小夥伴理清思緒。

單向綠色箭頭:

  • 前端模板 -> Controller:表示這個前端模板中有一個超連結是由這個 Controller 處理的

  • Controller -> 前端模板:表示這個 Controller 會像該前端模板傳遞資料或者跳轉

雙向綠色箭頭:表示 Controller 和前端模板之間進行引數的相互傳遞或使用

單向藍色箭頭: A -> B,表示 A 方法呼叫了 B 方法

單向紅色箭頭:資料庫或快取操作

註冊

  • 使用者註冊成功,將使用者資訊存入 MySQL,但此時該使用者狀態為未啟用

  • 向使用者傳送啟用郵件,使用者點選連結則啟用賬號(Spring Mail)

備戰春招!開源社群系統 Echo 超全文件助力面試

登入 | 登出

  • 進入登入介面,動態生成驗證碼,並將驗證碼短暫存入 Redis(60 秒)

  • 使用者登入成功(驗證使用者名稱、密碼、驗證碼),生成登入憑證且設定狀態為有效,並將登入憑證存入 Redis

    注意:登入憑證存在有效期,在所有的請求執行之前,都會檢查憑證是否有效和是否過期,只要該使用者的憑證有效並在有效期時間內,本次請求就會一直持有該使用者資訊(使用 ThreadLocal 持有使用者資訊)

  • 勾選記住我,則延長登入憑證有效時間

  • 使用者登入成功,將使用者資訊短暫存入 Redis(1 小時)

  • 使用者登出,將憑證狀態設為無效,並更新 Redis 中該使用者的登入憑證資訊

下圖是登入模組的功能邏輯圖,並沒有使用 Spring Security 提供的認證邏輯(我覺得這個模組是最複雜的,這張圖其實很多細節還沒有畫全)

備戰春招!開源社群系統 Echo 超全文件助力面試

分頁顯示所有的帖子

  • 支援按照 “發帖時間” 顯示

  • 支援按照 “熱度排行” 顯示(Spring Quartz)

  • 將熱帖列表和所有帖子的總數存入本地快取 Caffeine(利用分散式定時任務 Spring Quartz 每隔一段時間就重新整理計算帖子的熱度/分數 — 見下文,而 Caffeine 裡的資料更新不用我們操心,它天生就會自動的更新它擁有的資料,給它一個初始化方法就完事兒)

備戰春招!開源社群系統 Echo 超全文件助力面試

 

賬號設定

  • 修改頭像(非同步請求)

    • 將使用者選擇的頭像圖片檔案上傳至七牛雲伺服器

  • 修改密碼

此處只畫出修改頭像:

備戰春招!開源社群系統 Echo 超全文件助力面試

釋出帖子(非同步請求)

備戰春招!開源社群系統 Echo 超全文件助力面試

顯示評論及相關資訊

評論部分前端的名稱顯示有些缺陷,有興趣的小夥伴歡迎提 PR 解決~

關於評論模組需要注意的就是評論表的設計,把握其中欄位的含義,才能透徹瞭解這個功能的邏輯。

評論 Comment 的目標型別(帖子,評論) entityType 和 entityId 以及對哪個使用者進行評論/回覆 targetId 是由前端傳遞給 DiscussPostController 的

備戰春招!開源社群系統 Echo 超全文件助力面試

一個帖子的詳情頁需要封裝的資訊大概如下:

備戰春招!開源社群系統 Echo 超全文件助力面試

新增評論(事務管理)

備戰春招!開源社群系統 Echo 超全文件助力面試

私信列表和詳情頁

備戰春招!開源社群系統 Echo 超全文件助力面試

傳送私信(非同步請求)

備戰春招!開源社群系統 Echo 超全文件助力面試

點贊(非同步請求)

將點贊相關資訊存入 Redis 的資料結構 set 中。其中,key 命名為 like:entity:entityType:entityId,value 即點贊使用者的 id。比如 key = like:entity:2:246 value = 11 表示使用者 11 對實體型別 2 即評論進行了點贊,該評論的 id 是 246

某個使用者的獲贊數量對應的儲存在 Redis 中的 key 是 like:user:userId,value 就是這個使用者的獲贊數量

備戰春招!開源社群系統 Echo 超全文件助力面試

我的獲贊數量

備戰春招!開源社群系統 Echo 超全文件助力面試

關注(非同步請求)

  • 若 A 關注了 B,則 A 是 B 的粉絲 Follower,B 是 A 的目標 Followee

  • 關注的目標可以是使用者、帖子、題目等,在實現時將這些目標抽象為實體(目前只做了關注使用者)

將某個使用者關注的實體相關資訊儲存在 Redis 的資料結構 zset 中:key 是 followee:userId:entityType ,對應的 value 是 zset(entityId, now) ,以關注的時間進行排序。比如說 followee:111:3 對應的value (20, 2020-02-03-xxxx),表明使用者 111 關注了實體型別為 3 即人(使用者),該帖子的 id 是 20,關注該帖子的時間是 2020-02-03-xxxx

同樣的,將某個實體擁有的粉絲相關資訊也儲存在 Redis 的資料結構 zset 中:key 是 follower:entityType:entityId,對應的 value 是 zset(userId, now),以關注的時間進行排序

備戰春招!開源社群系統 Echo 超全文件助力面試

關注列表

備戰春招!開源社群系統 Echo 超全文件助力面試

傳送系統通知

備戰春招!開源社群系統 Echo 超全文件助力面試

顯示系統通知

備戰春招!開源社群系統 Echo 超全文件助力面試

搜尋

備戰春招!開源社群系統 Echo 超全文件助力面試

類似的,置頂、加精也會觸發發帖事件,就不再圖裡面畫出來了。

置頂加精刪除(非同步請求)

備戰春招!開源社群系統 Echo 超全文件助力面試

網站資料統計

備戰春招!開源社群系統 Echo 超全文件助力面試

帖子熱度計算

每次發生點贊(給帖子點贊)、評論(給帖子評論)、加精的時候,就將這些帖子資訊存入快取 Redis 中,然後通過分散式的定時任務 Spring Quartz,每隔一段時間就從快取中取出這些帖子進行計算分數。

帖子分數/熱度計算公式:分數(熱度) = 權重 + 發帖距離天數

// 計算權重
double w = (wonderful ? 75 : 0) + commentCount * 10 + likeCount * 2;
// 分數 = 權重 + 發帖距離天數
double score = Math.log10(Math.max(w, 1))
       + (post.getCreateTime().getTime() - epoch.getTime()) / (1000 * 3600 * 24);

備戰春招!開源社群系統 Echo 超全文件助力面試

? 配套教程

想要自己從零開始實現這個專案或者深入理解的小夥伴,可以關注公眾號『飛天小牛肉』,回覆 Echo 獲取配套教程, 不僅會詳細解釋本專案涉及的各大技術點,還會彙總相關的常見面試題,目前尚在更新中

並推薦我的開源教程類專案 『 CS-Wiki 』,Gitee 推薦專案,目前已 1.0k+ star: 致力打造完善的 Java 後端知識體系,不僅僅幫助各位小夥伴快速且系統的準備面試(秋招/社招),更指引學習的方向

相關文章