Java单表怎么实现评论回复功能
1.简介
评论功能有多种实现方式:
单层型
套娃型(多层型)
两层型
单层型:

套娃型:

两层型:

2.功能实现图

3.数据库设计
这个地方有个answer_id 很容易让人迷糊:是回复哪个用户的id
CREATE TABLE `tb_blog_comments` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键', `user_id` bigint(20) UNSIGNED NOT NULL COMMENT '用户id', `blog_id` bigint(20) UNSIGNED NOT NULL COMMENT '探店id', `parent_id` bigint(20) UNSIGNED NOT NULL COMMENT '关联的1级评论id,如果是一级评论,则值为0', `answer_id` bigint(20) UNSIGNED NOT NULL COMMENT '回复的评论id', `content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '回复的内容', `liked` int(8) UNSIGNED NULL DEFAULT 0 COMMENT '点赞数', `status` tinyint(1) UNSIGNED NULL DEFAULT 0 COMMENT '状态,0:正常,1:被举报,2:禁止查看', `create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '创建时间', `update_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = COMPACT; SET FOREIGN_KEY_CHECKS = 1;
4.实体类
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; import java.io.Serializable; import java.time.LocalDateTime; import java.util.List; /** ** *
* * @author 尹稳健 * @since 2022-11-09 */ @Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @TableName("tb_blog_comments") public class BlogComments implements Serializable { private static final long serialVersionUID = 1L; /** * 主键 */ @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 用户id */ private Long userId; /** * 探店id */ private Long blogId; /** * 关联的1级评论id,如果是一级评论,则值为0 */ private Long parentId; /** * 回复的评论id */ private Long answerId; /** * 回复的内容 */ private String content; /** * 点赞数 */ private Integer liked; /** * 状态,0:正常,1:被举报,2:禁止查看 */ private Boolean status; /** * 创建时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; /** * 更新时间 */ private LocalDateTime updateTime; /** * 是否点赞 */ @TableField(exist = false) private Boolean isLike; /** * 子评论 */ @TableField(exist = false) Listchildren; /** * 评论者的昵称 */ @TableField(exist = false) private String nickName; /** 评论者的头像 */ @TableField(exist = false) private String icon; /** 评论者的上级昵称 */ @TableField(exist = false) private String pNickName; /** 评论者的的上级头像 */ @TableField(exist = false) private String pIcon; }
5.实现思路
因为有评论区有两层,所以肯定有一个parent_id,这样你才能知道你是哪个评论下面的回复内容,如果继续评论,那么那条评论的parent_id还是之前那条评论的parent_id,而不是那条子评论的id。
回复内容也同样是一个评论实体类,只不过是一个集合,所以用List 存储,泛型使用实体类
我的功能实现也用到了父评论的用户名和头像,这样可以更好看出这是谁评论的,回复给谁的评论
6.功能实现
6.1 Sql入手
首先,我们需要知道自己需要哪些数据,返回给前端
如果你连mybatis都不会,那就看下思路吧
从这里获取到了评论表的所有数据,以及评论的人的信息,比如说昵称、头像、id,可以展示在前端
对应的mapper接口
package com.sky.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.sky.pojo.BlogComments; import org.apache.ibatis.annotations.Mapper; import java.util.List; /** ** Mapper 接口 *
* * @author 尹稳健 * @since 2022-11-09 */ @Mapper public interface BlogCommentsMapper extends BaseMapper{ /** * 查询所有的评论信息 * @param blogId * @return */ List findCommentDetail(Long blogId); }
6.2 业务实现
1.首先我们需要从数据中获取所有的数据
2.然后我们需要找到所有的一级评论,一级评论就是最高级,他不在谁的下面,他就是最大的,我这里在添加评论的时候前端做了处理,只要是一级评论,他的paren_id = 0
3.然后我们需要从一级评论下面添加他下面所有的子评论
最主要的就是如何将父级评论的信息添加到自己的数据中?
4.通过子评论中的paren_id 找到父评论,然后通过子评论的answer_id == 父评论的user_id 这样就可以拿到父评论的那一条数据
最后通过Optional 添加到子评论的数据中
@Override
public Result showBlogComments(Long blogId) {
// 先将数据库中的数据全部查询出来,包括评论作者的信息,昵称和头像
List blogComments = blogCommentsMapper.findCommentDetail(blogId);
// 获取所有的一级评论
List rootComments = blogComments.stream().filter(blogComments1 -> blogComments1.getParentId() == 0).collect(Collectors.toList());
// 从一级评论中获取回复评论
for (BlogComments rootComment : rootComments) {
// 回复的评论
List comments = blogComments.stream()
.filter(blogComment -> blogComment.getParentId().equals(rootComment.getId()))
.collect(Collectors.toList());
// 回复评论中含有父级评论的信息
comments.forEach(comment -> {
// 无法判断pComment是否存在,可以使用Optional
Optional pComment
= blogComments
.stream()
// 获取所有的评论的回复id也就是父级id的userid,这样就可以获取到父级评论的信息
.filter(blogComment -> comment.getAnswerId().equals(blogComment.getUserId())).findFirst();
// 这里使用了Optional 只有pcomment!=null 的时候才会执行下面的代码
pComment.ifPresent(v -> {
comment.setPNickName(v.getNickName());
comment.setPIcon(v.getIcon());
});
// 判断是否点赞
isBlogCommentLiked(comment);
});
rootComment.setChildren(comments);
// 判断是否点赞
isBlogCommentLiked(rootComment);
}
return Result.ok(rootComments);
} 7.前端实现
因为前端代码很多,只copy关键代码
{{comment.nickName}}{{comment.createTime}}{{comment.liked}} 回复 删除{{comment.content}}
{{reply.nickName}} 回复: {{reply.pnickName}}{{reply.createTime}}{{reply.liked}} 回复 删除{{reply.content}}