随笔 - 88  文章 - 0  评论 - 12  阅读 - 83814

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 

 作者:☜好脾气先生✔  

posted on   法哈席基  阅读(3636)  评论(4编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示