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

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

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

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

一、分类方式

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

绝大多数时候我们都会去使用两层型的评论方式做评论

Java实现评论回复功能的更多相关文章

  1. PHP无限级评论回复功能实现

    protected function commentList($aid,$pid = 0,&$result=array()){ $arr = ArticleComment::relation( ...

  2. C# + Javascript 实现评论回复功能

    首先先介绍一下前台 <script type="text/javascript"> function openWindow() { window.open(" ...

  3. 原生JS 将时间转换成几秒前,几分钟前…常用于评论回复功能

    //格式化时间 留备用~ function getDateDiff(dateStr) { var publishTime = dateStr / 1000, d_seconds, d_minutes, ...

  4. 利用php做出简单的发布信息和回复功能

    题目要求 1.建一个pinglun的数据库,自己建表2.完成一个简单的发布信息回复功能3.布局可以随便,主要是功能要实现4.注意回复是可以回复每一条的评论5.评论回复功能类似于qq空间的发布信息和回复 ...

  5. falsk sqlalchemy 自关联创建评论回复数据库

    本项目在于创建类似微信上的评论回复功能的数据库 基类: from app import db from datetime import datetime class Basemadel(object) ...

  6. 微信朋友圈评论/回复/cell/键盘谈起

    微信朋友圈评论功能的细节考虑及实现       微信朋友圈回复tableview iOS 实现微信朋友圈评论回复功能(一)

  7. PHP实现简单的评论与回复功能还有删除信息

    我们首先先看一下功能 上面黑色的是评论的下面红色的字体是回复的 再来看看怎么实现的 1.发布评论 <form action="pinglunchili.php" method ...

  8. 纯代码实现WordPress评论回复自动添加@评论者的功能

    先看看效果: 这个有什么用呢?添加了@功能之后那些用户评论之间的层次关系就很清晰了,我们可以清楚地知道这些评论是谁发给谁的. 其实主要是为了提升逼格. 实现方法: 将下面代码加入function.ph ...

  9. wordpress评论回复自动发邮件的功能

    A.插件流,可以说WP强大的插件功能的确能省事不少. 插件的办法一般是两步:第一实现成功发邮件,第二时间评论自动回复,这就需要用到两个插件,一个是Configure SMTP,一个是Mail To C ...

随机推荐

  1. Python练习题 042:Project Euler 014:最长的考拉兹序列

    本题来自 Project Euler 第14题:https://projecteuler.net/problem=14 ''' Project Euler: Problem 14: Longest C ...

  2. 卧槽!最新编程语言排名,Java 沦为老二。。

    2020 年 9 月刚过去,栈长看了下最新的 tiobe 编程语言榜,牛逼啊,C 语言居然登顶了,Java 下降 3 个点,沦为老二的位置. 数据来源TIOBE: https://www.tiobe. ...

  3. C++中try&catch

    参考:   https://blog.csdn.net/xueluowutong/article/details/81257654 在c++中,可以直接抛出异常之后自己进行捕捉处理,如:(这样就可以在 ...

  4. Pock 把 Touch Bar 变成系统中的 Dock 栏

    Pock 把 Touch Bar 变成系统中的 Dock 栏 Pock 是一款 macOS App,你可以通过它把 Touch Bar 变成系统中的 Dock 栏,直接用来切换和启动 App,尽享全屏 ...

  5. 笔记本电脑为什么有时候不用按FN+F1~12也可以控制音量、亮度全部等等

    对于经常要使用F1~F12的用户就很烦,比如编写前端代码的时候想直接按F12检查代码就是不行. 如何取消快捷键? 问题原因: 1.电脑默认使用了快捷键. 2.电脑按了FN+ESC锁定,只限于戴尔的电脑 ...

  6. 多测师讲解常用的测试工具分为10类_高级讲师肖sir

    我们将常用的测试工具分为10类. 1. 测试管理工具 2. 接口测试工具 3. 性能测试工具 4. C/S自动化工具 5.白盒测试工具 6.代码扫描工具 7.持续集成工具 8.网络测试工具 9.app ...

  7. FY2E HDF格式数据处理绘图

    圆盘标称投影数据时静止气象卫星常见的数据产品,比如FY2E静止气象卫星就有很多这样的产品(可以从国家卫星气象中心网站上下载).所谓的圆盘标称投影就是Geostationary投影,主要的投影参数有中央 ...

  8. centos7安装redis6

    wget http://download.redis.io/releases/redis-6.0.6.tar.gz?_ga=2.104030464.1049731693.1595900008-1330 ...

  9. 关于Dockerfile

    在Docker中创建镜像最常用的方式,就是使用Dockerfile.Dockerfile是一个Docker镜像的描述文件,我们可以理解成火箭发射的A.B.C.D-的步骤.Dockerfile其内部包含 ...

  10. nginx 是如何处理过期事件的?

    目录 什么是过期事件 nginx 是如何处理过期事件的? 参考资料 什么是过期事件 对于不需要加入到 post 队列 延后处理的事件,nginx 的事件都是通过 ngx_epoll_process_e ...