feat(comment): 实现二级评论分页查询功能
- 新增子评论分页查询接口 /comment/child/list- 添加查询一级评论下子评论总数的 Mapper 方法 - 实现二级评论分页数据查询的 Mapper 方法 - 补充对应的 XML 查询语句,支持按 parent_id 查询子评论 - 创建 FindChildCommentItemRspVO 和 FindChildCommentPageListReqVO VO 类 - 在 CommentServiceImpl 中实现子评论分页查询业务逻辑 - 支持批量查询子评论内容及用户信息并组装返回数据 - 添加 HTTP 客户端测试用例用于验证接口功能
This commit is contained in:
@@ -3,9 +3,7 @@ package com.hanserwei.hannote.comment.biz.controller;
|
||||
import com.hanserwei.framework.biz.operationlog.aspect.ApiOperationLog;
|
||||
import com.hanserwei.framework.common.response.PageResponse;
|
||||
import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.hannote.comment.biz.model.vo.FindCommentItemRspVO;
|
||||
import com.hanserwei.hannote.comment.biz.model.vo.FindCommentPageListReqVO;
|
||||
import com.hanserwei.hannote.comment.biz.model.vo.PublishCommentReqVO;
|
||||
import com.hanserwei.hannote.comment.biz.model.vo.*;
|
||||
import com.hanserwei.hannote.comment.biz.service.CommentService;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -35,4 +33,10 @@ public class CommentController {
|
||||
return commentService.findCommentPageList(findCommentPageListReqVO);
|
||||
}
|
||||
|
||||
@PostMapping("/child/list")
|
||||
@ApiOperationLog(description = "二级评论分页查询")
|
||||
public PageResponse<FindChildCommentItemRspVO> findChildCommentPageList(@Validated @RequestBody FindChildCommentPageListReqVO findChildCommentPageListReqVO) {
|
||||
return commentService.findChildCommentPageList(findChildCommentPageListReqVO);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -82,4 +82,24 @@ public interface CommentDOMapper extends BaseMapper<CommentDO> {
|
||||
* @return 热门评论
|
||||
*/
|
||||
List<CommentDO> selectHeatComments(Long noteId);
|
||||
|
||||
/**
|
||||
* 查询一级评论下子评论总数
|
||||
*
|
||||
* @param commentId 一级评论 ID
|
||||
* @return 一级评论下子评论总数
|
||||
*/
|
||||
Long selectChildCommentTotalById(Long commentId);
|
||||
|
||||
/**
|
||||
* 查询二级评论分页数据
|
||||
*
|
||||
* @param parentId 一级评论 ID
|
||||
* @param offset 偏移量
|
||||
* @param pageSize 页大小
|
||||
* @return 二级评论分页数据
|
||||
*/
|
||||
List<CommentDO> selectChildPageList(@Param("parentId") Long parentId,
|
||||
@Param("offset") long offset,
|
||||
@Param("pageSize") long pageSize);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.hanserwei.hannote.comment.biz.model.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class FindChildCommentItemRspVO {
|
||||
|
||||
/**
|
||||
* 评论 ID
|
||||
*/
|
||||
private Long commentId;
|
||||
|
||||
/**
|
||||
* 发布者用户 ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 评论内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 评论内容
|
||||
*/
|
||||
private String imageUrl;
|
||||
|
||||
/**
|
||||
* 发布时间
|
||||
*/
|
||||
private String createTime;
|
||||
|
||||
/**
|
||||
* 被点赞数
|
||||
*/
|
||||
private Long likeTotal;
|
||||
|
||||
/**
|
||||
* 回复的用户昵称
|
||||
*/
|
||||
private String replyUserName;
|
||||
|
||||
/**
|
||||
* 回复的用户 ID
|
||||
*/
|
||||
private Long replyUserId;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.hanserwei.hannote.comment.biz.model.vo;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class FindChildCommentPageListReqVO {
|
||||
|
||||
@NotNull(message = "父评论 ID 不能为空")
|
||||
private Long parentCommentId;
|
||||
|
||||
@NotNull(message = "页码不能为空")
|
||||
private Integer pageNo = 1;
|
||||
}
|
||||
@@ -4,9 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hanserwei.framework.common.response.PageResponse;
|
||||
import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentDO;
|
||||
import com.hanserwei.hannote.comment.biz.model.vo.FindCommentItemRspVO;
|
||||
import com.hanserwei.hannote.comment.biz.model.vo.FindCommentPageListReqVO;
|
||||
import com.hanserwei.hannote.comment.biz.model.vo.PublishCommentReqVO;
|
||||
import com.hanserwei.hannote.comment.biz.model.vo.*;
|
||||
|
||||
public interface CommentService extends IService<CommentDO> {
|
||||
/**
|
||||
@@ -24,4 +22,12 @@ public interface CommentService extends IService<CommentDO> {
|
||||
* @return 响应
|
||||
*/
|
||||
PageResponse<FindCommentItemRspVO> findCommentPageList(FindCommentPageListReqVO findCommentPageListReqVO);
|
||||
|
||||
/**
|
||||
* 二级评论分页查询
|
||||
*
|
||||
* @param findChildCommentPageListReqVO 二级评论分页查询参数
|
||||
* @return 响应
|
||||
*/
|
||||
PageResponse<FindChildCommentItemRspVO> findChildCommentPageList(FindChildCommentPageListReqVO findChildCommentPageListReqVO);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.hanserwei.framework.biz.context.holder.LoginUserContextHolder;
|
||||
import com.hanserwei.framework.common.constant.DateConstants;
|
||||
import com.hanserwei.framework.common.exception.ApiException;
|
||||
@@ -22,9 +23,7 @@ import com.hanserwei.hannote.comment.biz.domain.mapper.CommentDOMapper;
|
||||
import com.hanserwei.hannote.comment.biz.domain.mapper.NoteCountDOMapper;
|
||||
import com.hanserwei.hannote.comment.biz.enums.ResponseCodeEnum;
|
||||
import com.hanserwei.hannote.comment.biz.model.dto.PublishCommentMqDTO;
|
||||
import com.hanserwei.hannote.comment.biz.model.vo.FindCommentItemRspVO;
|
||||
import com.hanserwei.hannote.comment.biz.model.vo.FindCommentPageListReqVO;
|
||||
import com.hanserwei.hannote.comment.biz.model.vo.PublishCommentReqVO;
|
||||
import com.hanserwei.hannote.comment.biz.model.vo.*;
|
||||
import com.hanserwei.hannote.comment.biz.retry.SendMqRetryHelper;
|
||||
import com.hanserwei.hannote.comment.biz.rpc.DistributedIdGeneratorRpcService;
|
||||
import com.hanserwei.hannote.comment.biz.rpc.KeyValueRpcService;
|
||||
@@ -300,6 +299,133 @@ public class CommentServiceImpl extends ServiceImpl<CommentDOMapper, CommentDO>
|
||||
return PageResponse.success(commentRspVOS, pageNo, count, pageSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResponse<FindChildCommentItemRspVO> findChildCommentPageList(FindChildCommentPageListReqVO findChildCommentPageListReqVO) {
|
||||
// 父评论 ID
|
||||
Long parentCommentId = findChildCommentPageListReqVO.getParentCommentId();
|
||||
// 当前页码
|
||||
Integer pageNo = findChildCommentPageListReqVO.getPageNo();
|
||||
// 每页展示的二级评论数 (小红书 APP 中是一次查询 6 条)
|
||||
long pageSize = 6;
|
||||
|
||||
// TODO:先从缓存中查询,待完善
|
||||
|
||||
// 查询一级评论下的子评论数目
|
||||
Long count = commentDOMapper.selectChildCommentTotalById(parentCommentId);
|
||||
|
||||
// 若一级评论不存在或者评论数目为0,则直接返回
|
||||
if (Objects.isNull(count) || count == 0) {
|
||||
return PageResponse.success(null, pageNo, 0);
|
||||
}
|
||||
|
||||
// 分页返回参数VO
|
||||
List<FindChildCommentItemRspVO> childCommentRspVOS = Lists.newArrayList();
|
||||
|
||||
// 计算分页查询的偏移量offset(需要加1,因为最早回复的二级评论已经被展示了)
|
||||
long offset = PageResponse.getOffset(pageNo, pageSize) + 1;
|
||||
|
||||
// 分页查询子评论
|
||||
List<CommentDO> childCommentDOS = commentDOMapper.selectChildPageList(parentCommentId, offset, pageSize);
|
||||
|
||||
// 调用KV服务需要的入参
|
||||
List<FindCommentContentReqDTO> findCommentContentReqDTOS = Lists.newArrayList();
|
||||
// 调用用户服务需要的入参
|
||||
Set<Long> userIds = Sets.newHashSet();
|
||||
|
||||
// 归属的笔记ID
|
||||
Long noteId = null;
|
||||
|
||||
// 循环提取RPC调用所需要的入参数据
|
||||
for (CommentDO childCommentDO : childCommentDOS) {
|
||||
noteId = childCommentDO.getNoteId();
|
||||
// 构建调用KV服务批量查询评论内容的入参
|
||||
Boolean isContentEmpty = childCommentDO.getIsContentEmpty();
|
||||
if (!isContentEmpty) {
|
||||
FindCommentContentReqDTO findCommentContentReqDTO = FindCommentContentReqDTO.builder()
|
||||
.contentId(childCommentDO.getContentUuid())
|
||||
.yearMonth(DateConstants.DATE_FORMAT_Y_M.format(childCommentDO.getCreateTime()))
|
||||
.build();
|
||||
findCommentContentReqDTOS.add(findCommentContentReqDTO);
|
||||
}
|
||||
// 构建调用用户服务批量查询用户信息入参
|
||||
userIds.add(childCommentDO.getUserId());
|
||||
|
||||
Long parentId = childCommentDO.getParentId();
|
||||
Long replyCommentId = childCommentDO.getReplyCommentId();
|
||||
// 若当前评论的 replyCommentId 不等于 parentId,则前端需要展示回复的哪个用户,如 “回复 Hanserwei:”
|
||||
if (!Objects.equals(parentId, replyCommentId)) {
|
||||
userIds.add(childCommentDO.getReplyUserId());
|
||||
}
|
||||
}
|
||||
|
||||
// RPC 调用KV服务批量查询评论内容
|
||||
List<FindCommentContentRspDTO> findCommentContentRspDTOS = keyValueRpcService.batchFindCommentContent(noteId, findCommentContentReqDTOS);
|
||||
|
||||
// DTO转Map方便后续拼接数据
|
||||
Map<String, String> commentUuidAndContentMap = null;
|
||||
if (CollUtil.isNotEmpty(findCommentContentRspDTOS)) {
|
||||
commentUuidAndContentMap = findCommentContentRspDTOS.stream()
|
||||
.collect(Collectors.toMap(FindCommentContentRspDTO::getContentId, FindCommentContentRspDTO::getContent));
|
||||
}
|
||||
|
||||
// RPC 调用用户服务批量查询用户信息
|
||||
List<FindUserByIdRspDTO> findUserByIdRspDTOS = userRpcService.findByIds(userIds.stream().toList());
|
||||
|
||||
// DTO转Map方便后续拼接数据
|
||||
Map<Long, FindUserByIdRspDTO> userIdAndDTOMap = null;
|
||||
if (CollUtil.isNotEmpty(findUserByIdRspDTOS)) {
|
||||
userIdAndDTOMap = findUserByIdRspDTOS.stream()
|
||||
.collect(Collectors.toMap(FindUserByIdRspDTO::getId, e -> e));
|
||||
}
|
||||
|
||||
// DO 转 VO
|
||||
for (CommentDO childCommentDO : childCommentDOS) {
|
||||
// 构建 VO 实体类
|
||||
Long userId = childCommentDO.getUserId();
|
||||
FindChildCommentItemRspVO childCommentRspVO = FindChildCommentItemRspVO.builder()
|
||||
.userId(userId)
|
||||
.commentId(childCommentDO.getId())
|
||||
.imageUrl(childCommentDO.getImageUrl())
|
||||
.createTime(DateUtils.formatRelativeTime(childCommentDO.getCreateTime()))
|
||||
.likeTotal(childCommentDO.getLikeTotal())
|
||||
.build();
|
||||
|
||||
// 填充用户信息(包括评论发布者、回复的用户)
|
||||
if (CollUtil.isNotEmpty(userIdAndDTOMap)) {
|
||||
FindUserByIdRspDTO findUserByIdRspDTO = userIdAndDTOMap.get(userId);
|
||||
// 评论发布者用户信息(头像、昵称)
|
||||
if (Objects.nonNull(findUserByIdRspDTO)) {
|
||||
childCommentRspVO.setAvatar(findUserByIdRspDTO.getAvatar());
|
||||
childCommentRspVO.setNickname(findUserByIdRspDTO.getNickName());
|
||||
}
|
||||
|
||||
// 评论回复的哪个
|
||||
Long replyCommentId = childCommentDO.getReplyCommentId();
|
||||
Long parentId = childCommentDO.getParentId();
|
||||
|
||||
if (Objects.nonNull(replyCommentId)
|
||||
&& !Objects.equals(replyCommentId, parentId)) {
|
||||
Long replyUserId = childCommentDO.getReplyUserId();
|
||||
FindUserByIdRspDTO replyUser = userIdAndDTOMap.get(replyUserId);
|
||||
childCommentRspVO.setReplyUserName(replyUser.getNickName());
|
||||
childCommentRspVO.setReplyUserId(replyUser.getId());
|
||||
}
|
||||
}
|
||||
|
||||
// 评论内容
|
||||
if (CollUtil.isNotEmpty(commentUuidAndContentMap)) {
|
||||
String contentUuid = childCommentDO.getContentUuid();
|
||||
if (StringUtils.isNotBlank(contentUuid)) {
|
||||
childCommentRspVO.setContent(commentUuidAndContentMap.get(contentUuid));
|
||||
}
|
||||
}
|
||||
|
||||
childCommentRspVOS.add(childCommentRspVO);
|
||||
}
|
||||
|
||||
return PageResponse.success(childCommentRspVOS, pageNo, count, pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步评论详情到本地缓存中
|
||||
*
|
||||
|
||||
@@ -154,4 +154,30 @@
|
||||
order by heat desc
|
||||
limit 500
|
||||
</select>
|
||||
|
||||
<select id="selectChildCommentTotalById" resultType="long">
|
||||
select child_comment_total
|
||||
from t_comment
|
||||
where id = #{commentId}
|
||||
and level = 1
|
||||
</select>
|
||||
|
||||
<select id="selectChildPageList" resultMap="BaseResultMap" parameterType="map">
|
||||
select id,
|
||||
user_id,
|
||||
note_id,
|
||||
content_uuid,
|
||||
is_content_empty,
|
||||
image_url,
|
||||
like_total,
|
||||
create_time,
|
||||
reply_user_id,
|
||||
parent_id,
|
||||
reply_comment_id
|
||||
from t_comment
|
||||
where parent_id = #{parentId}
|
||||
and level = 2
|
||||
order by id
|
||||
limit #{offset}, #{pageSize}
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -356,3 +356,13 @@ Content-Type: application/json
|
||||
"noteId": 1862481582414102549,
|
||||
"pageNo": 1
|
||||
}
|
||||
|
||||
### 分页查询子评论
|
||||
POST http://localhost:8000/comment/comment/child/list
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"parentCommentId": 4002,
|
||||
"pageNo": 1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user