『博客开发日记-后台』之获取评论列表接口的实现

本文最后更新于 2026年5月3日 上午

获取评论列表接口的实现


获取评论列表接口的需求

根据关键字模糊查询评论名称

根据状态筛选

根据评论类型筛选

根据审核状态筛选

根据文章来筛选(当评论类型选择文章评论时)

按创建时间倒序排列

要有树状结构


代码实现

创建 CommentController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* 评论管理接口
*/
@RestController
@RequestMapping("/comments")
@Api(tags = "评论管理", description = "评论管理相关接口")
public class CommentController
{
@Autowired
private AdminCommentService adminCommentService;

@GetMapping
@SystemLog(businessName = "分页查询评论列表")
@ApiOperation(value = "评论列表", notes = "分页查询评论列表", response = PageVo.class)
@ApiImplicitParams({
@ApiImplicitParam(name = "pageNum", value = "页号", dataType = "int", paramType = "query"),
@ApiImplicitParam(name = "pageSize", value = "每页数量", dataType = "int", paramType = "query"),
@ApiImplicitParam(name = "keywords", value = "搜索关键字", dataType = "string", paramType = "query"),
@ApiImplicitParam(name = "type", value = "评论类型", dataType = "string", paramType = "query"),
@ApiImplicitParam(name = "status", value = "审核状态", dataType = "string", paramType = "query"),
@ApiImplicitParam(name = "articleId", value = "文章ID", dataType = "string", paramType = "query"),
@ApiImplicitParam(name = "startTime", value = "开始时间", dataType = "string", paramType = "query"),
@ApiImplicitParam(name = "endTime", value = "结束时间", dataType = "string", paramType = "query")
})
public ResponseResult getCommentList(Integer pageNum, Integer pageSize, @Valid CommentListDto commentListDto)
{
return adminCommentService.getCommentList(pageNum, pageSize, commentListDto);
}
}

创建 CommentListDto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* 评论列表请求DTO
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "评论列表请求对象")
public class CommentListDto {

@ApiModelProperty(value = "关键字(用于模糊搜索评论内容)", example = "测试")
private String keywords;

@Pattern(regexp = "^$|^[012]$", message = "评论类型只能为0、1或2")
@ApiModelProperty(value = "评论类型(0-文章评论,1-友链留言,2-留言板)", example = "0")
private String type;

@Pattern(regexp = "^$|^[01]$", message = "状态只能为0或1")
@ApiModelProperty(value = "审核状态(0-正常,1-待审核)", example = "0")
private String status;

@ApiModelProperty(value = "文章ID", example = "123")
private String articleId;

@ApiModelProperty(value = "开始时间", example = "2026-04-01 00:00:00")
private String startTime;

@ApiModelProperty(value = "结束时间", example = "2026-04-30 23:59:59")
private String endTime;
}


创建 AdminCommentListVo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/**
* 后台评论管理VO
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "后台评论管理响应对象")
public class AdminCommentListVo {

@ApiModelProperty(value = "评论ID")
private String id;

@ApiModelProperty(value = "评论类型(0-文章评论,1-友链留言,2-留言板)")
private String type;

@ApiModelProperty(value = "文章ID")
private String articleId;

@ApiModelProperty(value = "文章标题")
private String articleTitle;

@ApiModelProperty(value = "用户ID")
private String userId;

@ApiModelProperty(value = "昵称")
private String nickname;

@ApiModelProperty(value = "邮箱")
private String email;

@ApiModelProperty(value = "个人网址")
private String personalWebsite;

@ApiModelProperty(value = "评论内容")
private String content;

@ApiModelProperty(value = "根评论ID")
private Long rootId;

@ApiModelProperty(value = "回复目标评论的用户昵称")
private String replyToNickname;

@ApiModelProperty(value = "点赞数")
private Integer likeCount;

@ApiModelProperty(value = "审核状态(0-正常,1-待审核)")
private String status;

@ApiModelProperty(value = "创建时间")
private String createTime;

@ApiModelProperty(value = "子评论列表")
private List<AdminCommentListVo> children;
}


创建 AdminCommentService

1
2
3
4
5
6
7
8
9
10
/**
* 后台评论管理服务接口
*
* @author mengze
*/
public interface AdminCommentService {
ResponseResult getCommentList(Integer pageNum, Integer pageSize, CommentListDto commentListDto);
}



创建 AdminCommentServiceImpl 并在其中实现方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/**
* 评论管理服务实现类
*
* @author mengze
*/
@Service
public class AdminCommentServiceImpl implements AdminCommentService
{
@Autowired
private CommentMapper commentMapper;

@Autowired
private ArticleMapper articleMapper;

@Override
public ResponseResult getCommentList(Integer pageNum, Integer pageSize, CommentListDto commentListDto)
{
//构建查询条件
LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();

//关键字模糊搜索评论内容
queryWrapper.like(StringUtils.hasText(commentListDto.getKeywords()), Comment::getContent, commentListDto.getKeywords());

//评论类型筛选
queryWrapper.eq(StringUtils.hasText(commentListDto.getType()), Comment::getType, commentListDto.getType());

//审核状态筛选
queryWrapper.eq(StringUtils.hasText(commentListDto.getStatus()), Comment::getStatus, commentListDto.getStatus());

//文章ID筛选(type=0,即为文章评论时)
if (StringUtils.hasText(commentListDto.getArticleId())
&& SystemConstants.COMMENT_TYPE_ARTICLE.equals(commentListDto.getType())) {
queryWrapper.eq(Comment::getArticleId, Long.parseLong(commentListDto.getArticleId()));
}

//时间范围筛选
queryWrapper.ge(StringUtils.hasText(commentListDto.getStartTime()), Comment::getCreateTime, commentListDto.getStartTime())
.le(StringUtils.hasText(commentListDto.getEndTime()), Comment::getCreateTime, commentListDto.getEndTime());

//按创建时间倒序排列
queryWrapper.orderByDesc(Comment::getCreateTime);

//分页查询
Page<Comment> page = new Page<>(pageNum, pageSize);
commentMapper.selectPage(page, queryWrapper);

//转换为VO并构建树形结构
List<AdminCommentListVo> commentVoList = buildCommentTree(page.getRecords());

return ResponseResult.okResult(new PageVo(commentVoList, page.getTotal()));
}

//构建评论树形结构
private List<AdminCommentListVo> buildCommentTree(List<Comment> comments)
{
if (comments == null || comments.isEmpty()) {
return new ArrayList<>();
}

//先转换为VO列表
List<AdminCommentListVo> allVoList = toAdminCommentVoList(comments);

//使用Map存储所有评论,key为评论ID
Map<String, AdminCommentListVo> commentMap = allVoList.stream()
.collect(Collectors.toMap(AdminCommentListVo::getId, vo -> vo));

//分离根评论和子评论
List<AdminCommentListVo> rootComments = new ArrayList<>();

for (AdminCommentListVo vo : allVoList) {
if (vo.getRootId() == null || vo.getRootId() == -1) {
//根评论
rootComments.add(vo);
} else {
//子评论,找到父评论并其添加到children中
String rootIdStr = String.valueOf(vo.getRootId());
AdminCommentListVo rootComment = commentMap.get(rootIdStr);
if (rootComment != null) {
rootComment.getChildren().add(vo);
} else {
//如果找不到根评论(可能不在当前页),则作为根评论处理
rootComments.add(vo);
}
}
}

return rootComments;
}

//转换为AdminCommentVo列表
private List<AdminCommentListVo> toAdminCommentVoList(List<Comment> comments)
{
if (comments == null || comments.isEmpty()) {
return new ArrayList<>();
}

//批量查询文章标题(避免N+1查询)
List<Long> articleIds = comments.stream()
.filter(c -> c.getArticleId() != null && c.getArticleId() > 0)
.map(Comment::getArticleId)
.distinct()
.collect(Collectors.toList());

Map<Long, String> articleTitleMap = new HashMap<>();
if (!articleIds.isEmpty()) {
List<Article> articles = articleMapper.selectBatchIds(articleIds);
articleTitleMap = articles.stream()
.collect(Collectors.toMap(Article::getId, Article::getTitle));
}

//批量查询回复目标昵称
List<Long> replyToCommentIds = comments.stream()
.filter(c -> c.getReplyToCommentId() != null && c.getReplyToCommentId() > 0)
.map(Comment::getReplyToCommentId)
.distinct()
.collect(Collectors.toList());

Map<Long, String> replyToNicknameMap = new HashMap<>();
if (!replyToCommentIds.isEmpty()) {
List<Comment> replyToComments = commentMapper.selectBatchIds(replyToCommentIds);
replyToNicknameMap = replyToComments.stream()
.collect(Collectors.toMap(Comment::getId, Comment::getNickname));
}

//转换为VO
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
List<AdminCommentListVo> voList = new ArrayList<>();

for (Comment comment : comments)
{
AdminCommentListVo vo = new AdminCommentListVo();
vo.setId(String.valueOf(comment.getId()));

//直接使用数字类型
vo.setType(comment.getType());

// 设置文章信息
if (comment.getArticleId() != null && comment.getArticleId() > 0) {
vo.setArticleId(String.valueOf(comment.getArticleId()));
vo.setArticleTitle(articleTitleMap.get(comment.getArticleId()));
}

//设置用户信息
if (comment.getUserId() != null) {
vo.setUserId(String.valueOf(comment.getUserId()));
}
vo.setNickname(comment.getNickname());
vo.setEmail(comment.getEmail());
vo.setPersonalWebsite(comment.getPersonalWebsite());

//设置评论内容
vo.setContent(comment.getContent());
vo.setRootId(comment.getRootId());

//设置回复目标昵称
if (comment.getReplyToCommentId() != null && comment.getReplyToCommentId() > 0) {
vo.setReplyToNickname(replyToNicknameMap.get(comment.getReplyToCommentId()));
}

vo.setLikeCount(comment.getLikeCount());
vo.setStatus(comment.getStatus());
vo.setCreateTime(sdf.format(comment.getCreateTime()));

//子评论列表初始化为空
vo.setChildren(new ArrayList<>());

voList.add(vo);
}

return voList;
}
}

测试接口




PS:该系列只做为作者学习开发项目做的笔记用

不一定符合读者来学习,仅供参考


预告

后续会记录博客的开发过程

每次学习会做一份笔记来进行发表

“一花一世界,一叶一菩提”


版权所有 © 2026 云梦泽
欢迎访问我的个人网站:https://hgt12.github.io/


『博客开发日记-后台』之获取评论列表接口的实现
http://example.com/2026/04/30/『博客开发日记-后台』之获取评论列表接口的实现/
作者
云梦泽
发布于
2026年4月30日
更新于
2026年5月3日
许可协议