参考:
https://www.jb51.net/article/198874.htm
一、概述
这篇文章主要给大家介绍了关于Java实现评论回复功能的完整步骤
评论功能或许是大多数的单体应用之中会用到的功能,我们会在自己所开发的项目之中进行集成该功能
大多数时候我们会将评论功能划分成以下几种:
- 单一型
- 嵌套型
- 两层型
1、单一型
单一型评论方式就是日常论坛之中的盖楼的方式
用户只能根据所在的文章或者问题进行单一回复,评论之间没有互动
类似于问答形式。提出问题,然后回答,一对多关系。这些回答之间没有任何联系
2、嵌套型【不推荐】
嵌套型评论方式会对有回复的评论进行递归,会造成后端性能不佳,而且对于前端的展示也不是很友好
3、两层型
两层型评论方式就是除了一级评论之外,无论是对于该评论的回复还是对于回复的回复都统一在第二层
Bilibili评论回复功能就采用的是两层型


总结:
- 评论可以被回复,回复也可以被回复;
- 针对某篇文章或视频的评论,在第一级目录;
针对某个评论的回复或者回复的回复在二级目录(回复的回复格式上要区别于直接对评论的回复);
二、实现原理
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.javaprivate 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": []}]}]
绝大多数时候我们都会去使用两层型的评论方式做评论
