评论回复功能设计与总结-Java(两层型)

本文介绍了三种常见的评论系统分类方式:单一型、嵌套型和两层型,并详细解析了其实现原理。在单一型中,评论仅有一级;嵌套型虽然能体现互动,但可能导致性能问题;两层型则在互动和简洁间取得平衡。文章以博客评论为例,探讨了如何使用数据库设计和递归方法实现两层型评论,以提高效率和用户体验。
摘要由CSDN通过智能技术生成


使用递归循环开发评论回复功能,适用于大部分的简单单体应用

评论功能或许是大多数的单体应用之中会用到的功能,我们会在自己所开发的项目之中进行集成该功能

大多数时候我们会将评论功能划分成以下几种:

  • 单一型
  • 嵌套型
  • 两层型

一、分类方式

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;
  • DTO设计
    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="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=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": []
        }
      ]
    }
  ]

绝大多数时候我们都会去使用两层型的评论方式做评论
具体实现就是mapper.xml文件之中的mybatis嵌套查询
和serviceImpl实现层之中的递归整合,代码思路很简单,希望能对有需要的朋友有所帮助

两层型的评论功能代码在这里,有需要的朋友可以去看看
两层评论模型

附录:

两层型数据库设计表DDL语法示例

-- auto-generated definition
create table video_comment
(
    id          varchar(64)                                       not null comment '主键id'
        primary key,
    remark      varchar(255)                                      null comment '备注',
    create_by   varchar(64)                                       null comment '创建者',
    create_time timestamp(6) default CURRENT_TIMESTAMP(6)         not null on update CURRENT_TIMESTAMP(6) comment '创建时间',
    update_by   varchar(64)                                       null comment '更新者',
    update_time timestamp(6) default '0000-00-00 00:00:00.000000' not null comment '更新时间',
    enable      tinyint(1)   default 1                            null comment '逻辑删除值',
    user_id     varchar(64)                                       null comment '用户id',
    content     varchar(255)                                      null comment '评论内容',
    video_id    varchar(64)                                       null comment '评论视频id',
    status      int(2)       default 1                            null comment '审核状态(0待审核,1,审核通过,2审核不通过)',
    parent_id   varchar(64)  default '0'                          not null comment '父id'
)
    comment '视频评论表';


在这里插入图片描述

  • 13
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 28
    评论
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值