场景应用:设计一个论坛的评论回复功能

Posted 流楚丶格念

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了场景应用:设计一个论坛的评论回复功能相关的知识,希望对你有一定的参考价值。

文章目录

评论回复功能样式的分类

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查询出来,传递给前端展示出来即可,在XML映射文件中我们就可以这么查

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 '评论表';

在XML映射文件中我们就可以这么查,当然此时要设置resultMap了

我们要先设计DTO:

List<ContentDTO> children;就是存当前评论下嵌套的评论

@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;

查询语句如下

<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>

resultMap如下,children成员需要嵌套一条条的评论再查一遍

<resultMap id="commentDTOMap" type="com.yyl.comment.entity.ContentDTO">
    <id property="id" column="id"></id>
    <result property="nickname" column="nickname"></result>
    <result property="content" column="content"></result>

    <association property="children"
                 select="com.yyl.comment.mapper.ContentMapper.selectCommentById" column="blogId=blog_id,parentId=id"
                 fetchType="lazy">
    </association>
</resultMap>

例如我们查到的结果如下:

[
    
      "id": "1309302063977304065",
      "nickname": "评论1",
      "content": "你还好吗?",
      "children": [
        
          "id": "1309319425866698753",
          "nickname": "1",
          "content": "我很好",
          "children": []
        
      ]
    ,
    
      "id": "1309341283121154994",
      "nickname": "评论2",
      "content": "你还在嘛?",
      "children": [
        
          "id": "1309373675783184385",
          "nickname": "评论1的评论1",
          "content": "我不在",
          "children": [
            
              "id": "1309373886580514817",
              "nickname": "评论1的评论1的评论1",
              "content": "你不在你在哪?",
              "children": [
                  
                      "id": "1309373675783184385",
                      "nickname": "评论1的评论1的评论1的评论1",
                      "content": "你管人家在哪",
                      "children": []
                  
              ]
            
          ]
        
      ]
    
]

3、两层(二级)型

数据库设计与嵌套型保持一致,只需要在查询出来数据之后对数据进行处理即可。

【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 '评论表';

DTO如下:

List<ContentDTO> children;就是存当前评论下嵌套的评论

@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;

此时我们就没办法再映射文件中去处理子级评论了,因为不管是当前评论下,嵌套了多少层的评论,都需要加到当前评论的回复列表下,嵌套很多层的评论与回复,脱离了与一级评论的直接关系,无法直接通过关系映射绑定到当前一级评论下,所以我们此时就要编写业务层代码来处理,代码如下:

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": []
        
      ]
    
  ]

绝大多数时候我们都会去使用两层型的评论方式做评论,具体实现就是mapper.xml文件之中的mybatis嵌套查询

以上是关于场景应用:设计一个论坛的评论回复功能的主要内容,如果未能解决你的问题,请参考以下文章

论坛的SQL回复表怎么设计

评论回复功能设计

数据库设计——评论回复功能

Drupal:评论的访问限制

Java单表实现评论回复功能

Discuz!论坛实现帖子回复可见内容功能