博客评论层级回复前后端实现(vue+springboot)

自己也搭建了个新的博客,部分文章与csdn同步.本文在我的新博客同样可以看到:
http://spzgczyj.top/blog/article.html?articleId=350

致谢

首先感谢下面三个博主提供是思路:

Vue 递归组件_任重道远-CSDN博客_vue中什么是递归组件

vue递归组件实现多级列表 - 菲H - 博客园

评论系统数据库设计及实现 - Mario_Xue - 博客园

我的项目是前后端分离的,后台给前端带有层级的json格式的文件,前端用vue渲染。这时候就出现了两个问题:

1. 前端vue渲染层级的回复需要递归,而我当时只会简单的v-for。

2. 后台数据库设计如何在3nf范式的前提下实现评论层级回复的存储,如果要查询出来,sql应该如何写,这搞搞就变成了SQL递归查询的问题,但是我们其实就不是很喜欢查询的时候用到SQL递归查询,搞搞就变得复杂了。一旦递归查询,效率就会很慢时间复杂度就和层数挂钩了。

后端实现

针对这两个问题,我先找到了后台的实现,我从评论系统数据库设计及实现 - Mario_Xue - 博客园 这位博主的文章找到了思路,

我的评论表字段是这样的:

博客评论层级回复前后端实现(vue+springboot)_第1张图片

不需要多余的表,一张表就够了。

这是我的实体类:

package com.gkd.blog.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.lang.NonNull;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import java.util.Date;
import java.util.List;

/**
 * 

description: 评论和该评论的用户信息

*

create: 2020/1/10 12:15

* @author zhaoyijie * @version v1.0 */ @Data @ToString @NoArgsConstructor @AllArgsConstructor @JsonInclude(JsonInclude.Include.NON_NULL) public class CommentAndUser { /** * 评论id */ private Integer id; /** * 文章id */ private Integer articleId; /** * 游客的昵称 */ @NotBlank private String visitorName; /** * 游客的邮箱 */ @NonNull @Pattern(regexp= "^[A-Za-z]{1,40}@[A-Za-z0-9]{1,40}\\\\.[A-Za-z]{2,3}$") private String userEmaill; /** * 评论日期 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date addTime; /** * 评论内容 */ @NotBlank private String commentContent; /** * 评论父id */ private Integer parentId; /** * 子评论列表,回复评论 */ private List childList; }

针对这个表和实体类,先查询数据出来再组装数据:

List allList = commentMapper.findAllCommentByArticleId(articleId);
        Map map = new HashMap<>();
        List result = new ArrayList<>();
        for (CommentAndUser c : allList) {
            if (c.getParentId() == null) {
                result.add(c);
            }
            map.put(c.getId(), c);
        }
        for (CommentAndUser c : allList) {
            if (c.getParentId() != null) {
                CommentAndUser parent = map.get(c.getParentId());
               
                if (parent == null) {
                    continue;
                }
                
                if (parent.getId().intValue() == c.getId().intValue()) {
                    continue;
                }
                if (parent.getChildList() == null) {
                    parent.setChildList(new ArrayList<>());
                }
                parent.getChildList().add(c);
            }
        }

 这里result是最后返回给前端的数据列表,当然需要分页后再写成json返回给前端,这里时间复杂度就O(n)。而不是递归那种O(n^2)了。这里需要说明的是在遍历allList的时候,我们需要判断一下中的parent是否为null,理论上这个不应该需要考虑,因为子评论有父id,那肯定是找得到父评论的,但是,如果数据被人为不小心或者故意删除了父评论,但是子评论还携带父id,这样子map取出来就是null,null操作就会报错,所以为了保险,还是得先判断从map取出来的父评论对象是否为空。接着还得判断一下父评论的id是否等于子评论的id,这是一个坑,虽然正常操作下这种情况是不可能出现的,但是一旦数据库存着这种错误的数据,子评论的父id居然是自己,那么最后写成json会递归调用,自己调用自己最后一定会栈溢出。所以必须得加个保险。

前端实现

针对前端的渲染,我选用了vue.js。主要是我前端并不是很会,然后找了很多篇文章,发现都是.vue文件的,我并不喜欢,不是import 就是 exports。拜托,我只会简单的v-for和new vue的方式,找了好久找不到我想要的,然后我找到了这两篇博主的文章:

Vue 递归组件_任重道远-CSDN博客_vue中什么是递归组件

vue递归组件实现多级列表 - 菲H - 博客园

最后整合了一下把前端代码写了出来,这里只放关键代码

 然后大功告成,最后的结果长这样:

博客评论层级回复前后端实现(vue+springboot)_第2张图片

你可能感兴趣的:(springboot,java,vue)