Java實現評論回復功能


前言

使用遞歸循環開發評論回復功能,適用於大部分的簡單單體應用

評論功能或許是大多數的單體應用之中會用到的功能,我們會在自己所開發的項目之中進行集成該功能

大多數時候我們會將評論功能划分成以下幾種:

  • 單一型
  • 嵌套型
  • 兩層型

一、分類方式

1、單一型

單一型評論方式就是日常論壇之中的蓋樓的方式

用戶只能根據所在的文章或者問題進行單一回復,評論之間沒有互動

類似於問答形式。提出問題,然后回答,一對多關系。這些回答之間沒有任何聯系

2、嵌套型

嵌套型評論方式會對有回復的評論進行遞歸,會造成后端性能不佳,而且對於前端的展示也不是很友好

3、兩層型(推薦使用,本人親測)

兩層型評論方式就是除了一級評論之外,無論是對於該評論的回復還是對於回復的回復都統一在第二層

二、實現原理

就以最常見的博客來說,不同的分類方式實現原理不一樣

1、單一型

我們只需要在評論的數據表格中添加博客id即可,查詢出相對應的數據直接進行展示即可

create table `comment` (
 `id` int(11) not null auto_increment comment '主鍵id',
 `nickname` varchar(255) default null comment '評論者昵稱',
 `avatar` varchar(255) comment '評論頭像',
 `content` varchar(255) default null comment '評論的內容',
 `blog_id` int(11) default null comment '評論的博客id',
 primary key (`id`)
 ) comment '評論表';

在業務之中根據博客id查詢出來,傳遞給前端展示出來即可

select * from comment where blog_id=#{blog_id}

2、嵌套型

嵌套型的評論方式所需要的數據結構是樹狀型的,評論多起來的話層級結構會變得很復雜,對於性能消耗也是很巨大,【不推薦】

實現原理為我們會在評論表之中添加一個【parent_id】字段,定義評論和回復為父子級的關系,評論為父級,回復為子級,默認為【-1】,表示為沒有父級,

create table `comment` (
 `id` int(11) not null auto_increment comment '主鍵id',
 `nickname` varchar(255) default null comment '評論者昵稱',
 `avatar` varchar(255) comment '評論頭像',
 `content` varchar(255) default null comment '評論的內容',
 `blog_id` int(11) default null comment '評論的博客id',
 `parent_id` int(11) default '-1' comment '父級評論id',
 primary key (`id`)
 ) comment '評論表';

需要使用遞歸和鏈表進行循環遍歷插入回復

設計如下:

Content.java

private static final long serialVersionUID = 1L;
 
@ApiModelProperty(value = "主鍵id")
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Integer id;
 
@ApiModelProperty(value = "用戶昵稱")
@TableField("nickname")
private String nickname;
 
@ApiModelProperty(value = "頭像")
@TableField("avatar")
private String avatar;
 
@ApiModelProperty(value = "評論")
@TableField("comment")
private String comment;
 
@ApiModelProperty(value = "博客id ")
@TableField("blog_id")
private Integer blogId;
 
@ApiModelProperty(value = "回復評論id")
@TableField("parent_id")
private Integer parentId;

ContentDTO.java

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@ApiModel(value = "評論模型")
@JsonIgnoreProperties(value = { "handler" })
public class ContentDTO {
    private int id;
 private String nickname;
 private String content;
    private List<ContentDTO> children;
}

使用mybatis做為持久層框架,編寫sql查詢語句進行嵌套查詢,

<resultMap id="commentDTOMap" type="com.zukxu.items.comment.entity.ContentDTO">
 <id property="id" column="comment_id"></id>
 <result property="nickname" column="nickname"></result>
 <result property="content" column="content"></result>
 
 <association property="children"
     select="com.zukxu.items.comment.mapper.ContentMapper.selectCommentById" column="{blogId=blog_id,parentId=comment_id}"
     fetchType="lazy">
 </association>
</resultMap>
 
<select id="selectCommentById" resultMap="commentDTOMap">
 SELECT comment_id,nickname,content,blog_id,parent_id FROM blog WHERE blog_id = #{blogId} AND parent_id = #{parentId}
</select>

結果如下:

[
    {
      "id": "1309302063977304065",
      "nickname": "1",
      "content": "這次該可以了吧",
      "children": [
        {
          "id": "1309319425866698753",
          "nickname": "1",
          "content": "好了?",
          "children": []
        }
      ]
    },
    {
      "id": "1309341283121154994",
      "nickname": "4",
      "content": "為什么呢",
      "children": [
        {
          "id": "1309373849414787073",
          "nickname": "1",
          "content": "好了?",
          "children": []
        },
        {
          "id": "1309308402422091778",
          "nickname": "1",
          "content": "可以了吧",
          "children": []
        },
        {
          "id": "1309373675783184385",
          "nickname": "1",
          "content": "好了?",
          "children": [
            {
              "id": "1309373886580514817",
              "nickname": "1",
              "content": "???",
              "children": []
            }
          ]
        }
      ]
    }
  ]

結果會造成多重嵌套,不是很友好

3、兩層型

比單一型多了互動的功能,比嵌套型更加簡潔,方便操作管理
設計和嵌套型保持一致,只需要在查詢出來數據之后對數據進行處理即可
將嵌套型轉為兩層型結構

處理每個父級評論的子級及其嵌套子級

public List<CommentDTO> findParent(List<CommentDTO> comments) {
 
  for (CommentDTO comment : comments) {
 
   // 防止checkForComodification(),而建立一個新集合
   ArrayList<CommentDTO> fatherChildren = new ArrayList<>();
 
   // 遞歸處理子級的回復,即回復內有回復
   findChildren(comment, fatherChildren);
 
   // 將遞歸處理后的集合放回父級的孩子中
   comment.setChildren(fatherChildren);
  }
  return comments;
 }
 
 public void findChildren(CommentDTO parent, List<CommentDTO> fatherChildren) {
 
  // 找出直接子級
  List<CommentDTO> comments = parent.getChildren();
 
  // 遍歷直接子級的子級
  for (CommentDTO comment : comments) {
 
   // 若非空,則還有子級,遞歸
   if (!comment.getChildren().isEmpty()) {
    findChildren(comment, fatherChildren);
   }
 
   // 已經到了最底層的嵌套關系,將該回復放入新建立的集合
   fatherChildren.add(comment);
 
   // 容易忽略的地方:將相對底層的子級放入新建立的集合之后
   // 則表示解除了嵌套關系,對應的其父級的子級應該設為空
   comment.setChildren(new ArrayList<>());
  }
 }
}

最后的結果如下:

 [
    {
      "id": "1309302063977304065",
      "userId": "1",
      "comment": "這次該可以了吧",
      "children": [
        {
          "id": "1309319425866698753",
          "userId": "1",
          "comment": "好了?",
          "children": []
        }
      ]
    },
    {
      "id": "1309341283121154994",
      "userId": "4",
      "comment": "為什么呢",
      "children": [
        {
          "id": "1309373849414787073",
          "userId": "1",
          "comment": "好了?",
          "children": []
        },
        {
          "id": "1309308402422091778",
          "userId": "1",
          "comment": "可以了吧",
          "children": []
        },
        {
          "id": "1309373886580514817",
          "userId": "1",
          "comment": "???",
          "children": []
        },
        {
          "id": "1309373675783184385",
          "userId": "1",
          "comment": "好了?",
          "children": []
        }
      ]
    }
  ]

絕大多數時候我們都會去使用兩層型的評論方式做評論。

 

原文地址:https://www.jb51.net/article/198874.htm 

 作者:☜好脾氣先生✔  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM