1. 程式人生 > >評論功能的簡單實現

評論功能的簡單實現

****
> 最近在寫一個問答功能,類似於評論,幾番找資料才有點感覺(主要是太菜了),為了加深印象就單獨抽出來記下筆記,然後這篇寫完就開始SpringBoot的複習了
## 1. 說明 網上看到有三種類型的評論,按照筆者的理解記下了過程(可能理解錯了,望大神指出),所以列出的是筆者的理解,下面以模擬**部落格評論的場景**來說明,(這些型別是筆者形容的,並沒有這個詞),總覺得很慌理解錯了,希望大家評論指正
**測試環境:SSM、JDK1.8**



## 2. 沒有互動型 這種型別只能評論,評論之間沒有互動,類似於問答形式。提出問題,然後回答,一對多關係。這些回答之間沒有任何聯絡
![](https://img2020.cnblogs.com/blog/1737887/202003/1737887-20200308111934019-142211100.png) 從圖可以簡單看出,這種型別的評論是比較簡單的,設計一個評論表,其內部新增一個掛載的部落格id欄位即可
**資料庫設計** ```mysql CREATE TABLE `comment` ( `comment_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '評論的id', `nickname` varchar(255) DEFAULT NULL COMMENT '評論者的暱稱', `content` varchar(255) DEFAULT NULL COMMENT '評論的內容', `blog_id` int(11) DEFAULT NULL COMMENT '評論掛載的部落格id', PRIMARY KEY (`comment_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ``` 這裡主要說明評論功能的實現,表會盡可能簡單的設計,像點贊,分頁,影象這些不再考慮範圍內,另一個blog表也沒有給出,可以自行理解
**查詢語句** ```mysql SELECT * FROM comment WHERE blog_id = #{blog_id} ``` 傳入需要查詢評論的部落格id即可,將查詢的內容放入其評論區完成,這種評論較為簡單,評論之間沒有互動,適用於少數場景(像筆者這次寫的問答功能,但該問答有非法關鍵詞,官方回答,鎖定,稽核,等功能,也不簡單)



## 3. 套娃型 這種型別筆者見得比較少,因為像樹狀,評論多起來層級結構複雜,不人性化
![](https://img2020.cnblogs.com/blog/1737887/202003/1737887-20200308111948828-1043288399.png) 小一評論部落格,小二緊接著回覆小一的評論,小三又回覆小二的評論,小一又回了小三的評論,像俄羅斯套娃層層套
**資料庫設計** 這裡筆者用單表來實現,筆者稱評論與回覆這二者為父子關係,評論為父級,回覆為子級,這種關係在資料裡增多一個parent_id欄位來維護,預設為-1,表示沒有父級 ```mysql CREATE TABLE `blog` ( `comment_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '評論的id', `nickname` varchar(255) DEFAULT NULL COMMENT '評論者的暱稱', `content` varchar(255) DEFAULT NULL COMMENT '評論的內容', `blog_id` int(11) DEFAULT NULL COMMENT '評論掛載的部落格id', `parent_id` int(11) DEFAULT '-1' COMMENT '父級評論', PRIMARY KEY (`comment_id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; ``` 部落格評論多起來的時,可用blog_id作為索引(不想增加與功能無關內容,假裝沒看到)
**Dto、對映檔案、Service層** 由於使用mybatis,所以把對映檔案放上來一目瞭然 ```java public class CommentDTO { private int id; private String nickname; private String content; private List children; // 存放子級的回覆 // getter / setter } ``` ```xml
``` ```java @Service public class CommentService { @Autowired CommentDao commentDao; public List selectCommentById(int blogId) { // 預設傳入-1,即找出父級評論先 return commentDao.selectCommentById(blogId, -1); } } ```
這樣查詢出來的語句是層層套的,不信你看 ```json [{ "id": 1, "nickname": "小二", "content": "不錯", "children": [{ "id": 2, "nickname": "小三", "content": "支援", "children": [{ "id": 3, "nickname": "小四", "content": "6666", "children": [] }] }] }, { "id": 4, "nickname": "小五", "content": "一般般把", "children": [] }] ```



## 4. 兩層型 即只有兩層關係,比單層多了互動功能,比套娃簡潔,看圖
![](https://img2020.cnblogs.com/blog/1737887/202003/1737887-20200308112009179-1729716496.png) 這種看起來舒服多了,怎麼做到的呢? 其實和套娃型使用的是**同一個表與查詢**,對映檔案都不用改,不同之處在於查詢出來的後期的邏輯處理,很多時候跨庫也是如此,查完資料再進行邏輯的處理
### 處理邏輯 由套娃型轉變成二層型
**套娃的示意圖:** ![](https://img2020.cnblogs.com/blog/1737887/202003/1737887-20200308112022161-1259748508.png) - 1樓和2樓同級,屬於父級評論,直接掛載的部落格下 - A屬於1樓評論的子級 - B屬於A的子級 - C屬於B的子級
**二層的示意圖:** ![](https://img2020.cnblogs.com/blog/1737887/202003/1737887-20200308112054194-875155279.png) A,B,C 屬於同級,直接屬於1樓評論的子級
**處理邏輯程式碼** 業務邏輯在Service層,DTT測試 ```java @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class CommentServiceTest { @Autowired CommentDao commentDao; @Test public void selectCommentById() { // 預設傳入-1,找出父級的評論,假裝檢視部落格id為7的評論 List comments = commentDao.selectCommentById(7, -1); // 這裡將套娃關係處理為二層關係 System.out.println(JSON.toJSONString(findParent(comments))); } // 處理每個父級評論的子級及其巢狀子級 public List findParent(List comments) { for (CommentDTO comment : comments) { // 防止checkForComodification(),而建立一個新集合 ArrayList fatherChildren = new ArrayList<>(); // 遞迴處理子級的回覆,即回覆內有回覆 findChildren(comment, fatherChildren); // 將遞迴處理後的集合放回父級的孩子中 comment.setChildren(fatherChildren); } return comments; } public void findChildren(CommentDTO parent, List fatherChildren) { // 找出直接子級 List comments = parent.getChildren(); // 遍歷直接子級的子級 for (CommentDTO comment : comments) { // 若非空,則還有子級,遞迴 if (!comment.getChildren().isEmpty()) { findChildren(comment, fatherChildren); } // 已經到了最底層的巢狀關係,將該回復放入新建立的集合 fatherChildren.add(comment); // 容易忽略的地方:將相對底層的子級放入新建立的集合之後 // 則表示解除了巢狀關係,對應的其父級的子級應該設為空 comment.setChildren(new ArrayList<>()); } } } ``` 註釋清楚地說明了處理邏輯,但這種做法顯然不是很好的,可以有更優雅的處理方法,只是筆者還沒想到
**輸出結果** ```json [{ "id": 1, "nickname": "小二", "content": "不錯", "children": [{ "id": 3, "nickname": "小四", "content": "6666", "children": [] }, { "id": 2, "nickname": "小三", "content": "支援", "children": [] }] }, { "id": 4, "nickname": "小五", "content": "一般般把", "children": [] }] ```



> 後記:後期邏輯處理部分花了大半天沒濾清關係,沒想到第二天醒來隨手兩分鐘就搞定。原因:增強for底層使用了迭代器,修改結構會有快速失敗機制、還有處理二層關係的時候,最底層往上解除套娃關係時,記得將孩子置空