SpringBoot實現(xiàn)無限級評論回復的項目實踐
評論功能已經(jīng)成為APP和網(wǎng)站開發(fā)中的必備功能。本文采用springboot+mybatis-plus框架,通過代碼主要介紹評論功能的數(shù)據(jù)庫設計和接口數(shù)據(jù)返回。我們返回的格式可以分三種方案,第一種方案是先返回評論,再根據(jù)評論id返回回復信息,第二種方案是將評論回復直接封裝成一個類似于樹的數(shù)據(jù)結構進行返回(如果數(shù)據(jù)對的話,可以根據(jù)評論分頁),第三種方案是將所有數(shù)據(jù)用遞歸的SQL查出來,再把數(shù)據(jù)解析成樹,返回結果
1 數(shù)據(jù)庫表結構設計
表結構:
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;
數(shù)據(jù)添加:
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');
添加后的數(shù)據(jù):
2 方案一
方案一先返回評論列表,再根據(jù)評論id返回回復列表,以此循環(huán),具體代碼下文進行展示
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實現(xiàn)類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 數(shù)據(jù)庫持久層類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請求接口,查看返回數(shù)據(jù)
2.6.1 請求評論列表接口(本地的url為:http://localhost:8081/one/comment/ ,GET請求),請求結果如圖
2.6.2 根據(jù)評論id(或者回復id)返回回復列表(本地url為:http://localhost:8081/one/comment/parent/1 ,GET請求),請求結果如圖
3 方案二
方案二采用的是將數(shù)據(jù)裝到一個類似樹的數(shù)據(jù)結構,然后返回,數(shù)據(jù)如果多的話,可以根據(jù)評論列表進行分頁
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實現(xiàn)類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 參數(shù) */ @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 數(shù)據(jù)庫持久層類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請求接口,查看返回數(shù)據(jù)
3.6.1 通過遞歸的方式以樹的數(shù)據(jù)結構返回(本地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 方案三
方案三是將所有數(shù)據(jù)用遞歸的SQL查出來,再把數(shù)據(jù)解析成樹,返回結果,適合數(shù)據(jù)較少的情況下,且MySQL版本需要在8.0以上
4.1 控制層CommentThreeController.java
/** * @author wuKeFan * @date 2023-02-20 17:30:45 */ @Slf4j @RestController @RequestMapping("/three/comment") public class CommentThreeController { @Resource private CommentService commentService; @GetMapping("/") public List<CommentDTO> getAllCommentsBySql() { return commentService.getAllCommentsBySql(); } @PostMapping("/") public void addComment(@RequestBody Comment comment) { commentService.addComment(comment); } }
4.2 service類CommentService.java
/** * service類 * @author wuKeFan * @date 2023-02-20 16:55:23 */ public interface CommentService { List<CommentDTO> getAllCommentsBySql(); }
4.3 service實現(xiàn)類CommentServiceImpl.java
/** * @author wuKeFan * @date 2023-02-20 16:56:00 */ @Service public class CommentServiceImpl implements CommentService{ @Resource private CommentMapper baseMapper; /** * 遞歸獲取 * @param commentDTO 參數(shù) */ @Override public void setChildren(CommentDTO commentDTO){ List<CommentDTO> children = baseMapper.findByParentId(commentDTO.getId()); if (!children.isEmpty()) { commentDTO.setChildren(children); children.forEach(this::setChildren); } } }
4.4 數(shù)據(jù)庫持久層類CommentMapper.java
/** * mapper類 * @author wuKeFan * @date 2023-02-20 16:53:59 */ @Repository public interface CommentMapper extends BaseMapper<Comment> { @DS("localhost80") List<CommentDTO> getAllCommentsBySql(); }
4.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; private Integer level; }
4.6 使用Postman請求接口,查看返回數(shù)據(jù)
4.6.1 通過遞歸的方式以樹的數(shù)據(jù)結構返回(本地url為:http://localhost:8081/three/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": [], "createTime": "2023-02-21 09:56:27", "level": 4 } ], "createTime": "2023-02-20 17:12:13", "level": 3 }, { "id": 4, "parentId": 2, "content": "我回復了第一條評論的第二條回復", "author": "吳名氏", "children": [], "createTime": "2023-02-21 09:23:14", "level": 3 } ], "createTime": "2023-02-20 17:12:00", "level": 2 } ], "createTime": "2023-02-20 17:11:16", "level": 1 }, { "id": 5, "parentId": 0, "content": "這是評論2", "author": "吳名氏", "children": [], "createTime": "2023-02-21 09:41:02", "level": 1 } ]
5 總結
以上三種方案各有優(yōu)缺點,需要從不同場景中使用不同的方案,更多相關SpringBoot 無限級評論回復內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java NIO實例UDP發(fā)送接收數(shù)據(jù)代碼分享
這篇文章主要介紹了Java NIO實例UDP發(fā)送接收數(shù)據(jù)代碼分享,分享了客戶端和服務端完整代碼,小編覺得還是挺不錯的,共需要的朋友參考。2017-11-11Spring3.1.1+MyBatis3.1.1的增、刪、查、改以及分頁和事務管理
這篇文章主要介紹了Spring3.1.1+MyBatis3.1.1的增、刪、查、改以及分頁和事務管理的相關資料,需要的朋友可以參考下2016-01-01java多線程返回值使用示例(callable與futuretask)
這篇文章主要介紹了多線程返回值使用示例(callable與futuretask),需要的朋友可以參考下2014-04-04