关于实现一个评论或者留言功能的思路(个人博客开发的实现思路)

537 阅读3分钟

关于博客


博客技术栈

  • 前端页面用的 Onestar GitHub 直接从GitHub拿下来使用了
  • 后端采用SpringBoot + Mybatis-plus + Thymleaf 快速开发

博客碰到的问题

  • 评论区功能的重构

    初期想实现的评论区功能 一个顶级的父评论和其下面所有的子评论共同组成一个板块 依次嵌套展示

    对评论的回复的人 以 @名称 的形式


对应的初期表设计结构 意采用树的形式存储评论 即每个评论存储他回复的评论的ID 看起来没有什么问题

初期代码实现

思路: 将顶级父评论下所有的子评论组装到集合中(即不论是一级还是二级或者三级评论都组装到顶级父评论的子集合中) 并赋予父亲评论的名称 再放到前端展示 这里用递归
    
     /**
     * 父评论所属全部子评论
     */
    @TableField(exist = false)//在数据库表中忽略此列
    private List<Comment> children;

//  用于临时存储一个父
private List<Comment> temp = new ArrayList<>();

public List<Comment> listComment(Long id) {

        QueryWrapper<Comment> wrapper = new QueryWrapper<>();
        wrapper.eq("blog_id",id).orderByDesc("create_time");;
        List<Comment> list = baseMapper.selectList(wrapper);

        //  拿到父评论集合
        List<Comment> pComments = commentList
            .stream()
            .filter(comment -> comment.getParentCommentId() == 0)
            .collect(Collectors.toList());

        //  收集所有父评论的 全部子评论
        for (Comment pComment : pComments) {
            //  调用查找所有子评论
            getChildren(pComment.getId(),pComment.getNickname());
            // 查找完毕 设置到集合中
            pComment.setChildren(temp);
            //  重新置空 提供给下一个父节点使用
            temp = new ArrayList<>();
        }
        return pComments;
    }

    /**
     * 递归查找所有子评论
     */
    public void children(List<Comment> list,Long pId,String pName){
        List<Comment> collect = list
            .stream()
            .filter(comment -> comment.getParentCommentId() == pId)
            .collect(Collectors.toList());
        
         //  判断是否含有子评论
        if(collect.size()>0){
            for (Comment comment : collect) {
                //  设置他回复的评论的名称 即 @名称
                comment.setPNickName(pName);
                //  添加到临时集合中
                temp.add(comment);
                //  继续递归查找
                children(list,comment.getId(),comment.getNickname());
            }
        }
    }

实现效果也很理想 至少展示和添加评论没有什么问题 但是当我想实现一个 删除留言评论的功能时 发现了问题所在

  • 由于数据库表设计时每个评论的父ID放的都是他回复评论的父ID 而想删除时 如果当前子评论还有子评论 即一级评论有二级回复 当你想删除一级评论时 就会导致二级回复丢失 因为无法找到其父评论ID 再观察哔哩哔哩的评论功能时候发现是具备删除单个评论的功能的 于是就想办法解决

解决办法 增加一个字段 存储他回复的直接评论 的 评论昵称

parent_message_id 存放最顶级的父评论ID

这样展示的时候 既不需要递归查找组装(因为就是属于他的直接子评论) 也不需要手动的去赋值父评论的名称

 //  直接查找当前顶级父评论下的所有子评论 然后展示即可 即使删除评论 也无关紧要 因为是根据顶级父评论来查找评论的 且回复的评论名称已经用字段存储了   
 
public List<Comment> listComment(Long id) {

        QueryWrapper<Comment> wrapper = new QueryWrapper<>();
        wrapper.eq("blog_id",id).orderByDesc("create_time");;
        List<Comment> list = baseMapper.selectList(wrapper);
        //  拿到父评论集合
        List<Comment> pComments = list
                .stream()
                .filter(comment -> comment.getParentCommentId() == 0)
                .collect(Collectors.toList());
       //  组装子评论
        for (Comment pComment : pComments) {
            List<Comment> collect = list.stream()
                    .filter(comment -> pComment.getId().equals(comment.getParentCommentId()))
                    .collect(Collectors.toList());
            pComment.setChildren(collect);
        }
        
        return pComments;
    }