使用SpringBoot实现无限级评论回复功能

news2024/11/16 0:19:52

评论功能已经成为APP和网站开发中的必备功能。本文采用springboot+mybatis-plus框架,通过代码主要介绍评论功能的数据库设计和接口数据返回。我们返回的格式可以分两种方案,第一种方案是先返回评论,再根据评论id返回回复信息,第二种方案是将评论回复直接封装成一个类似于树的数据结构进行返回(如果数据对的话,可以根据评论分页)

1 数据库表结构设计

表结构:

CREATE TABLE `comment` (
  `id` bigint(18) NOT NULL AUTO_INCREMENT,
  `parent_id` bigint(18) NOT NULL DEFAULT '0',
  `content` text NOT NULL COMMENT '内容',
  `author` varchar(20) NOT NULL COMMENT '评论人',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '评论时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4;

数据添加:

INSERT INTO `comment` (`id`, `parent_id`, `content`, `author`, `create_time`) VALUES (1, 0, '这是评论1', '吴克翻', '2023-02-20 17:11:16');
INSERT INTO `comment` (`id`, `parent_id`, `content`, `author`, `create_time`) VALUES (2, 1, '我回复了第一条评论', '吴克翻', '2023-02-20 17:12:00');
INSERT INTO `comment` (`id`, `parent_id`, `content`, `author`, `create_time`) VALUES (3, 2, '我回复了第一条评论的第一条回复', '吴克翻', '2023-02-20 17:12:13');
INSERT INTO `comment` (`id`, `parent_id`, `content`, `author`, `create_time`) VALUES (4, 2, '我回复了第一条评论的第二条回复', '吴克翻', '2023-02-21 09:23:14');
INSERT INTO `comment` (`id`, `parent_id`, `content`, `author`, `create_time`) VALUES (5, 0, '这是评论2', '吴克翻', '2023-02-21 09:41:02');
INSERT INTO `comment` (`id`, `parent_id`, `content`, `author`, `create_time`) VALUES (6, 3, '我回复了第一条评论的第一条回复的第一条回复', '吴克翻', '2023-02-21 09:56:27');

添加后的数据:

2 方案一

方案一先返回评论列表,再根据评论id返回回复列表,以此循环,具体代码下文进行展示

2.1 控制层CommentOneController.java

/**
 * 方案一
 * @author wuKeFan
 * @date 2023-02-20 16:58:08
 */
@Slf4j
@RestController
@RequestMapping("/one/comment")
public class CommentOneController {

    @Resource
    private CommentService commentService;

    @GetMapping("/")
    public List<Comment> getList() {
        return commentService.getList();
    }

    @GetMapping("/{id}")
    public Comment getCommentById(@PathVariable Long id) {
        return commentService.getById(id);
    }

    @GetMapping("/parent/{parentId}")
    public List<Comment> getCommentByParentId(@PathVariable Long parentId) {
        return commentService.getCommentByParentId(parentId);
    }

    @PostMapping("/")
    public void addComment(@RequestBody Comment comment) {
        commentService.addComment(comment);
    }

}

2.2 service类CommentService.java

/**
 * service类
 * @author wuKeFan
 * @date 2023-02-20 16:55:23
 */
public interface CommentService {

    List<Comment> getCommentByParentId(Long parentId);

    void addComment(Comment comment);

    Comment getById(Long id);

    List<Comment> getList();
}

2.3 service实现类CommentServiceImpl.java

/**
 * @author wuKeFan
 * @date 2023-02-20 16:56:00
 */
@Service
public class CommentServiceImpl implements CommentService{

    @Resource
    private CommentMapper baseMapper;

    @Override
    public List<Comment> getCommentByParentId(Long parentId) {
        QueryWrapper<Comment> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", parentId);
        return baseMapper.selectList(queryWrapper);
    }

    @Override
    public void addComment(Comment comment) {
        baseMapper.insert(comment);
    }

    @Override
    public Comment getById(Long id) {
        return baseMapper.selectById(id);
    }

    @Override
    public List<Comment> getList() {
        return baseMapper.selectList(new QueryWrapper<Comment>().lambda().eq(Comment::getParentId, 0));
    }

}

2.4 数据库持久层类CommentMapper.java

/**
 * mapper类
 * @author wuKeFan
 * @date 2023-02-20 16:53:59
 */
@Repository
public interface CommentMapper extends BaseMapper<Comment> {

}

2.5 实体类Comment.java

/**
 * 评论表实体类
 * @author wuKeFan
 * @date 2023-02-20 16:53:24
 */
@Data
@TableName("comment")
public class Comment {
    @TableId(type = IdType.AUTO)
    private Long id;
    private Long parentId;
    private String content;
    private String author;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;
}

2.6 使用Postman请求接口,查看返回数据

2.6.1 请求评论列表接口(本地的url为:http://localhost:8081/one/comment/ ,GET请求),请求结果如图

2.6.2 根据评论id(或者回复id)返回回复列表(本地url为:http://localhost:8081/one/comment/parent/1 ,GET请求),请求结果如图

3 方案二

方案二采用的是将数据装到一个类似树的数据结构,然后返回,数据如果多的话,可以根据评论列表进行分页

3.1 控制层CommentTwoController.java

/**
 * @author wuKeFan
 * @date 2023-02-20 17:30:45
 */
@Slf4j
@RestController
@RequestMapping("/two/comment")
public class CommentTwoController {

    @Resource
    private CommentService commentService;

    @GetMapping("/")
    public List<CommentDTO> getAllComments() {
       return commentService.getAllComments();
    }

    @PostMapping("/")
    public void addComment(@RequestBody Comment comment) {
        commentService.addComment(comment);
    }
}

3.2 service类CommentService.java

/**
 * service类
 * @author wuKeFan
 * @date 2023-02-20 16:55:23
 */
public interface CommentService {

    void addComment(Comment comment);

    void setChildren(CommentDTO commentDTO);

    List<CommentDTO> getAllComments();
}

3.3 service实现类CommentServiceImpl.java

/**
 * @author wuKeFan
 * @date 2023-02-20 16:56:00
 */
@Service
public class CommentServiceImpl implements CommentService{

    @Resource
    private CommentMapper baseMapper;

    @Override
    public void addComment(Comment comment) {
        baseMapper.insert(comment);
    }

    @Override
    public List<CommentDTO> getAllComments() {
        List<CommentDTO> rootComments = baseMapper.findByParentId(0L);
        rootComments.forEach(this::setChildren);
        return rootComments;
    }

    /**
     * 递归获取
     * @param commentDTO 参数
     */
    @Override
    public void setChildren(CommentDTO commentDTO){
        List<CommentDTO> children = baseMapper.findByParentId(commentDTO.getId());
        if (!children.isEmpty()) {
            commentDTO.setChildren(children);
            children.forEach(this::setChildren);
        }
    }

}

3.4 数据库持久层类CommentMapper.java

/**
 * mapper类
 * @author wuKeFan
 * @date 2023-02-20 16:53:59
 */
@Repository
public interface CommentMapper extends BaseMapper<Comment> {

    @Select("SELECT id, parent_id as parentId, content, author, create_time as createTime FROM comment WHERE parent_id = #{parentId}")
    List<CommentDTO> findByParentId(Long parentId);

}

3.5 实体类CommentDTO.java

/**
 * 递归方式实体类
 * @author wuKeFan
 * @date 2023-02-20 17:26:48
 */
@Data
public class CommentDTO {

    private Long id;
    private Long parentId;
    private String content;
    private String author;
    private List<CommentDTO> children;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;

}

3.6 使用Postman请求接口,查看返回数据

3.6.1 通过递归的方式以树的数据结构返回(本地url为:http://localhost:8081/two/comment/ ,GET请求),请求结果如图

返回的json格式如图:

[
    {
        "id": 1,
        "parentId": 0,
        "content": "这是评论1",
        "author": "吴克翻",
        "children": [
            {
                "id": 2,
                "parentId": 1,
                "content": "我回复了第一条评论",
                "author": "吴克翻",
                "children": [
                    {
                        "id": 3,
                        "parentId": 2,
                        "content": "我回复了第一条评论的第一条回复",
                        "author": "吴克翻",
                        "children": [
                            {
                                "id": 6,
                                "parentId": 3,
                                "content": "我回复了第一条评论的第一条回复的第一条回复",
                                "author": "吴克翻",
                                "children": null,
                                "createTime": "2023-02-21 09:56:27"
                            }
                        ],
                        "createTime": "2023-02-20 17:12:13"
                    },
                    {
                        "id": 4,
                        "parentId": 2,
                        "content": "我回复了第一条评论的第二条回复",
                        "author": "吴克翻",
                        "children": null,
                        "createTime": "2023-02-21 09:23:14"
                    }
                ],
                "createTime": "2023-02-20 17:12:00"
            }
        ],
        "createTime": "2023-02-20 17:11:16"
    },
    {
        "id": 5,
        "parentId": 0,
        "content": "这是评论2",
        "author": "吴克翻",
        "children": null,
        "createTime": "2023-02-21 09:41:02"
    }
]

4 总结

以上两种方案各有优缺点,需要从不同场景中使用不同的方案

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/360327.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Coremail新春分享会:解读Coremail产品新亮点、邮件安全新趋势

2月15日&#xff0c;由Coremail主办的 “新年‘邮’新意 Coremail新春分享会”在线上直播间重磅开启&#xff01;现场分享精彩纷呈&#xff0c;好礼持续放送&#xff0c;场面火爆&#xff0c;收获观众过万点赞&#xff01; 直播现场 嘉宾分享了哪些行业干货&#xff1f;直播现场…

大数据开发-Linux环境搭建

1、操作系统 1.1 计算机原理 冯诺依曼结构&#xff1a;把程序当作数据存储在计算机存储设备中。 冯诺依曼三个基本原则&#xff1a; 采用二进制逻辑程序存储执行计算机由五个部分组成&#xff1a;运算器、控制器、储存器、输入和输出设备 计算机由软件和硬件组成&#xff0c…

图床(Typora + uPic/PicGo+ 七牛云)

图床&#xff08;Typora uPic/PicGo 七牛云&#xff09; 笔者平时使用 Typora 编写 markdown 文档&#xff0c;文档中常常会放置图片&#xff0c;如果文档不需要分享的话&#xff0c;其实讲图片存放在本地就可以了。由于我有在多台机器编写 markdown 笔记&#xff0c;还有将…

OAK相机跑各种yolo模型的检测帧率和深度帧率

编辑&#xff1a;OAK中国 首发&#xff1a;oakchina.cn 喜欢的话&#xff0c;请多多&#x1f44d;⭐️✍ 内容可能会不定期更新&#xff0c;官网内容都是最新的&#xff0c;请查看首发地址链接。 ▌前言 Hello&#xff0c;大家好&#xff0c;这里是OAK中国&#xff0c;我是助手…

Python字符串处理 -- 内附蓝桥题:门牌制作,卡片

字符串处理 ~~不定时更新&#x1f383;&#xff0c;上次更新&#xff1a;2023/02/20 &#x1f5e1;常用函数&#xff08;方法&#xff09; 1. s.count(str) --> 计算字符串 s 中有多少个 str 举个栗子&#x1f330; s "1354111" print(s.count(1)) # 答案为…

Docker 安装nacos并且配置数据库持久化(无脑CV版)

我们以运行ruoyi-cloud项目为例子 在安装之前请注意版本对应问题 https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E 由于我的是2021.0.4.0&#xff0c;因此安装2.0.4版本 否则可能会出现以下错误 在若依的issue有解决方案https:…

UnsupportedOperationException

原因&#xff1a;返回值为list时&#xff0c;返回值类型应为具体的类型参考文章&#xff1a;(139条消息) mybatis中返回结果类型为集合类型&#xff08;List、Map&#xff09;_毒毒毒毒丶的博客-CSDN博客_mybatis返回list<map>集合UnsupportedOperationException 是用于表…

【蓦然回首忆Java·基础卷Ⅱ】

文章目录对象内存解析方法的参数传递机制关键字&#xff1a;package、importpackage(包)JDK中主要的包介绍import(导入)JavaBeanUML类图继承的一些细节封装性中的4种权限修饰关键字&#xff1a;supersuper的理解super的使用场景子类中调用父类被重写的方法子类中调用父类中同名…

追梦之旅【数据结构篇】——详解C语言动态实现顺序表

详解C语言动态实现顺序表~&#x1f60e;前言&#x1f64c;顺序表概念及结构&#x1f64c;功能函数的具体实现分析&#xff1a;&#x1f64c;尾插函数具体实现&#xff1a;尾删函数具体实现&#xff1a;头插函数具体实现&#xff1a;头删插函数具体实现&#xff1a;任意插函数具…

EM算法总结

目录 一。Jensen不等式&#xff1a;若f是凸函数 二。最大似然估计 三。二项分布的最大似然估计 四。进一步考察 1.按照MLE的过程分析 2.化简对数似然函数 3.参数估计的结论 4.符合直观想象 五。从直观理解猜测GMM的参数估计 1.问题&#xff1a;随机变量无法直接…

SQL90 纠错3

描述OrderItems表含有order_num订单号order_numa002a002a002a004a007【问题】将下面代码修改正确后执行SELECT order_num, COUNT(*) AS items FROM OrderItems GROUP BY items HAVING COUNT(*) > 3 ORDER BY items, order_num;【示例结果】返回订单号order_num和出现的次数i…

数据结构之算法的时间复杂度和空间复杂度

本章重点&#xff1a; 1.算法效率 2.时间复杂度 3.空间复杂度 4. 常见时间复杂度以及复杂度oj练习 目录 1.算法效率 1.2算法的复杂度 2.时间复杂度 2.1 时间复杂度的概念 2.2 大O的渐进表示法 2.3常见时间复杂度计算举例 3.空间复杂度 4. 常见复杂度对比 5.复杂度…

在VMware Workstation中配置固定IP、在VMware Fusion中配置固定IP

1、在VMware Workstation中配置固定IP 配置固定IP需要2个大步骤&#xff1a; 1.在VMware Workstation&#xff08;或Fusion&#xff09;中配置IP地址网关和网段&#xff08;IP地址的范围&#xff09; 首先让我们&#xff0c;先进行第一步&#xff0c;跟随图片进行操作 现在进…

Pthreads实验

实验一&#xff1a;主线程与子线程 pthread_create函数&#xff1a; 1、简介&#xff1a;pthread_create是UNIX环境创建线程的函数 2、头文件&#xff1a;#include <pthread.h> 3、函数声明&#xff1a; int pthread_create(pthread_t* restrict tidp , const pthread_a…

java面试题-JUC锁

1.介绍下LockSupport&#xff1f;LockSupport 是 Java 并发包中的一个工具类&#xff0c;用于创建锁和其他同步类的基本线程阻塞原语。它也是 J.U.C 中的一个核心基础类。相较于 Object.wait() 和 Object.notify()&#xff0c;LockSupport 可以更加灵活地对线程进行阻塞和唤醒操…

以学校数据模型为例,掌握在DAS下使用GaussDB

文章目录题目具体操作一、表的创建二、表数据的插入三、数据查询目的&#xff1a; 这里以学校数据库模型为例&#xff0c;介绍GaussDB数据库、表等常见操作&#xff0c;以及SQL语法使用的介绍。题目 假设A市B学校为了加强对学校的管理&#xff0c;引入了华为GaussDB数据库。 在…

如何利用ChatGPT学习量化投资?

引言最近&#xff0c;ChatGPT持续火了很长时间&#xff0c;占领各大热点和头版头条&#xff0c;成为A股开年以来最大的热点之一。ChatGPT是OpenAI开发的一种语言生成模型&#xff0c;可以理解为智能问答机器人。最近围绕量化投资在上面试了很多问题&#xff0c;大部分回答还是很…

基于DSP+FPGA的机载雷达伺服控制系统的硬件设计与开发

机载雷达是以飞机为载体的各种雷达天线的总称&#xff0c;主要用于空中侦察、警戒、保 证航行准确与安全[1]。随着航空航天技术的飞速发展&#xff0c;以及微电子、计算机和高速集 成电路等新型技术在军事领域的广泛应用[2]&#xff0c;各国都研制出了许多新型战机和导弹,机 载…

docsify在线文档支持pdf查看

目录 步骤一&#xff1a;添加插件 步骤二&#xff1a;添加pdf地址 步骤三&#xff1a;成果展示 docsify是一个在github上很好用的文档转换网页的工具&#xff0c;但是大部分情况我们都是使用的markdown文件。最近想把pdf文档也能支持在这上面展示&#xff0c;研究后总结一下…

零信任-微软零信任概念补充(13)

​零信任是一种安全策略。 它不是产品或服务&#xff0c;而是设计和实现以下一组安全原则的方法&#xff1a; 显式验证使用最小特权访问假定数据泄露 零信任的指导原则 显式验证 使用最小特权 访问假定数据泄露 始终根据所有可用的数据点进行身份验证和授权。 使用实时和恰…