二级评论展示的实现方法
目录
前言
通常的博客评论展示有一级评论、二级评论、多级评论,不同的展示方法给用户的体验不一样。
一级评论
顾名思义,就是所有评论(回复)是同级关系,这样子是设计简单,查询迅速,表可以设计成:
字段 | 字段说明 |
---|---|
id | 主键 |
blog_id | 所属博客的id |
content | 评论内容 |
查询某一篇文章的评论时候可以使用
SELECT * FROM t_comment WHERE blog_id = 99;
是不是非常的简单!
但是这样子用户体验就太差了,对于回复的评论,用户根本无法建立起回复的桥梁。
多级评论
简单来说就是层层嵌套,每一条评论具有严格的父子关系。表格可以设计成:
字段 | 字段说明 |
---|---|
id | 主键 |
blog_id | 所属博客的id |
content | 评论内容 |
parent_comment_id | 父级评论id,顶层评论为-1 |
JavaBean
设计:
public class Comment {
private Long id;
private String content;
private Long blogId;
private Long parentCommentId;
private List<Comment> replyComments;
// 省略set和get方法
}
查询的时候,对于每一条顶层评论,拿到顶层评论的id
后,将该id
作为参数,可以查出二级评论,将二级评论的id
作为参数,可以查出三级评论......
借助Mybatis
,查询语句可以写成:
<mapper namespace="top.yalexin.rblog.mapper.CommentMapper">
<select id="findTopCommentsByParentIdAndBlogId" resultMap="topComment">
select * from t_comment as cmt where cmt.parent_comment_id=#{parentId} and cmt.blog_id=#{blogId}
</select>
<resultMap id="topComment" type="Comment">
<id column="id" property="id"></id>
<result property="content" column="content"/>
<result property="blogId" column="blog_id"/>
<result property="parentCommentId" column="parent_comment_id"/>
<!-- 这一步使得JDBC递归进行查询 -->
<association property="replyComments" select="findTopCommentsByParentIdAndBlogId"
column="{blogId=blog_id,parentId=id}"></association>
</resultMap>
</mapper>
查询结果类似于:
[
{
id: 1,
content: 'hello',
parent_comment_id: -1,
replyComments: [
{
id: 2,
content: 'hello',
parent_comment_id: 1,
replyComments:[
{
id: 3,
content: 'hello',
parent_comment_id: 2,
replyComments:[]
}
]
}
]
},
{
id: 4,
content: 'hello',
parent_comment_id: -1,
replyComments: []
}
]
类似的效果:
虽然看上去层级关系清晰明了,但是当回复树深度很大的时候,页面将变得十分难看,所以该方式也很少使用。
二级评论
该方式先把每一个顶级评论展示,然后每一个顶级评论下的所有评论都处理成二级评论
该方式查询过程也很简单,查询语句和多级评论的方式一样,需要改变的是查询结束后的处理:
如果将每一个顶级评论和该评论下的子孙评论看成一棵树的话,为每一个顶级评论创建一个replyCmts容器,那么我们可以递归进行,遇到叶节点时,将叶节点的父节点的replyComments设为空,同时将叶节点添加到replyCmts容器中,此时先前的父节点又变成了叶节点,此时就可以递归返回,直至处理完所有节点,下面是代码实现:
@Override
public List<Comment> getTopCommentsByBlogId(Long blogId) {
if (blogId == null || blogId < 0) return null;
List<Comment> rawCmts = commentMapper.findTopCommentsByParentIdAndBlogId((long) -1, blogId);
return getParent(rawCmts);
}
private List<Comment> getParent(List<Comment> rawComments) {
// 对于每一个顶级回复
for (Comment topComment : rawComments) {
// 将顶级评论的子孙评论归结到一个集合中
LinkedList<Comment> comments = new LinkedList<>();
List<Comment> replyCmtsByTopCmt = topComment.getReplyComments();
for (Comment replyComment : replyCmtsByTopCmt) {
handleChild(replyComment, comments);
// replyComment.setReplyNickname(topComment.getId().toString());
replyComment.setReplyNickname(topComment.getNickname());
}
topComment.setReplyComments(comments);
}
return rawComments;
}
//处理二级评论以及子评论
private void handleChild(Comment replyComment, List<Comment> parent) {
List<Comment> grandchildren = replyComment.getReplyComments();
replyComment.setReplyComments(null);
parent.add(replyComment);
for (Comment grandChild : grandchildren) {
// grandChild.setReplyNickname(replyComment.getId().toString());
grandChild.setReplyNickname(replyComment.getNickname());
if (grandChild.getReplyComments() != null) handleChild(grandChild, parent);
}
}
查询结果:
[
{
id: 1,
content: 'hello',
parent_comment_id: -1,
replyComments: [
{
id: 2,
content: 'hello',
parent_comment_id: 1,
replyComments:[]
},
{
id: 3,
content: 'hello',
parent_comment_id: 2,
replyComments:[]
}
]
},
{
id: 4,
content: 'hello',
parent_comment_id: -1,
replyComments: []
}
]
该方式结合了一级评论和多级评论的优点,深得广大开发者的热爱。
本文由「黄阿信」创作,创作不易,请多支持。
如果您觉得本文写得不错,那就点一下「赞赏」请我喝杯咖啡~
商业转载请联系作者获得授权,非商业转载请附上原文出处及本链接。
关注公众号,获取最新动态!
历史评论
开始评论