feat(comment): 实现评论分页查询功能

- 新增评论分页查询接口与实现逻辑
- 支持查询一级评论及其最早回复的二级评论
- 支持从KV服务批量获取评论内容
- 支持从用户服务批量获取用户信息并组装- 新增评论热度字段用于排序
- 修改MyBatis代码生成配置至comment模块
- 调整评论表结构,优化字段定义
- 完善相关DTO、VO及Mapper文件
- 添加HTTP客户端测试用例
This commit is contained in:
2025-11-08 11:07:50 +08:00
parent 2b06ca0300
commit fdee4dc2b4
19 changed files with 565 additions and 27 deletions

View File

@@ -9,11 +9,11 @@
<option name="deleteByPrimayKeyEnabled" value="false" /> <option name="deleteByPrimayKeyEnabled" value="false" />
<option name="insertMethodEnabled" value="false" /> <option name="insertMethodEnabled" value="false" />
<option name="insertSelectiveMethodEnabled" value="false" /> <option name="insertSelectiveMethodEnabled" value="false" />
<option name="javaMapperPackage" value="com.hanserwei.hannote.count.biz.domain.mapper" /> <option name="javaMapperPackage" value="com.hanserwei.hannote.comment.biz.domain.mapper" />
<option name="javaMapperPath" value="$PROJECT_DIR$/han-note-count/han-note-count-biz/src/main/java" /> <option name="javaMapperPath" value="$PROJECT_DIR$/han-note-comment/han-note-comment-biz/src/main/java" />
<option name="javaModelPackage" value="com.hanserwei.hannote.count.biz.domain.dataobject" /> <option name="javaModelPackage" value="com.hanserwei.hannote.comment.biz.domain.dataobject" />
<option name="javaModelPath" value="$PROJECT_DIR$/han-note-count/han-note-count-biz/src/main/java" /> <option name="javaModelPath" value="$PROJECT_DIR$/han-note-comment/han-note-comment-biz/src/main/java" />
<option name="lastDatabaseCrudChooseModuleName" value="han-note-count-biz" /> <option name="lastDatabaseCrudChooseModuleName" value="han-note-comment-biz" />
<option name="lombokAllArgConstructor" value="true" /> <option name="lombokAllArgConstructor" value="true" />
<option name="lombokDataAnnotation" value="true" /> <option name="lombokDataAnnotation" value="true" />
<option name="lombokNoArgsConstructor" value="true" /> <option name="lombokNoArgsConstructor" value="true" />
@@ -94,7 +94,7 @@
</entry> </entry>
</map> </map>
</option> </option>
<option name="mybatisPlusIdType" value="AUTO" /> <option name="mybatisPlusIdType" value="ASSIGN_ID" />
<option name="selectByPrimaryKeyEnabled" value="false" /> <option name="selectByPrimaryKeyEnabled" value="false" />
<option name="tableGenerateConfigs"> <option name="tableGenerateConfigs">
<map> <map>
@@ -144,7 +144,7 @@
<option name="insertMethodEnabled" value="false" /> <option name="insertMethodEnabled" value="false" />
<option name="insertSelectiveMethodEnabled" value="false" /> <option name="insertSelectiveMethodEnabled" value="false" />
<option name="javaModelName" value="CommentDO" /> <option name="javaModelName" value="CommentDO" />
<option name="moduleName" value="han-note-count-biz" /> <option name="moduleName" value="han-note-comment-biz" />
<option name="mybatisplusIdType" value="AUTO" /> <option name="mybatisplusIdType" value="AUTO" />
<option name="selectByPrimaryKeyEnabled" value="false" /> <option name="selectByPrimaryKeyEnabled" value="false" />
<option name="sequenceColumn" value="" /> <option name="sequenceColumn" value="" />
@@ -258,7 +258,7 @@
<option name="insertMethodEnabled" value="false" /> <option name="insertMethodEnabled" value="false" />
<option name="insertSelectiveMethodEnabled" value="false" /> <option name="insertSelectiveMethodEnabled" value="false" />
<option name="javaModelName" value="NoteCountDO" /> <option name="javaModelName" value="NoteCountDO" />
<option name="moduleName" value="han-note-count-biz" /> <option name="moduleName" value="han-note-comment-biz" />
<option name="mybatisplusIdType" value="ASSIGN_ID" /> <option name="mybatisplusIdType" value="ASSIGN_ID" />
<option name="selectByPrimaryKeyEnabled" value="false" /> <option name="selectByPrimaryKeyEnabled" value="false" />
<option name="sequenceColumn" value="" /> <option name="sequenceColumn" value="" />
@@ -427,7 +427,7 @@
<option name="updateByPrimaykeyEnabled" value="false" /> <option name="updateByPrimaykeyEnabled" value="false" />
<option name="userMybatisPlus" value="true" /> <option name="userMybatisPlus" value="true" />
<option name="xmlMapperPackage" value="mapperxml" /> <option name="xmlMapperPackage" value="mapperxml" />
<option name="xmlMapperPath" value="$PROJECT_DIR$/han-note-count/han-note-count-biz/src/main/resources" /> <option name="xmlMapperPath" value="$PROJECT_DIR$/han-note-comment/han-note-comment-biz/src/main/resources" />
</ProjectProfile> </ProjectProfile>
</option> </option>
</component> </component>

View File

@@ -125,6 +125,11 @@
<artifactId>spring-boot-starter-data-redis</artifactId> <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.hanserwei</groupId>
<artifactId>han-note-user-api</artifactId>
</dependency>
</dependencies> </dependencies>

View File

@@ -183,7 +183,10 @@ public class Comment2DBConsumer {
.toList(); .toList();
if (CollUtil.isNotEmpty(commentContentNotEmptyBOS)) { if (CollUtil.isNotEmpty(commentContentNotEmptyBOS)) {
// 批量存入评论内容 // 批量存入评论内容
keyValueRpcService.batchSaveCommentContent(commentContentNotEmptyBOS); boolean result = keyValueRpcService.batchSaveCommentContent(commentContentNotEmptyBOS);
if (!result) {
throw new RuntimeException("批量保存评论内容失败");
}
} }
return count; return count;

View File

@@ -1,7 +1,10 @@
package com.hanserwei.hannote.comment.biz.controller; package com.hanserwei.hannote.comment.biz.controller;
import com.hanserwei.framework.biz.operationlog.aspect.ApiOperationLog; 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.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.PublishCommentReqVO;
import com.hanserwei.hannote.comment.biz.service.CommentService; import com.hanserwei.hannote.comment.biz.service.CommentService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@@ -26,4 +29,10 @@ public class CommentController {
return commentService.publishComment(publishCommentReqVO); return commentService.publishComment(publishCommentReqVO);
} }
@PostMapping("/list")
@ApiOperationLog(description = "评论分页查询")
public PageResponse<FindCommentItemRspVO> findCommentPageList(@Validated @RequestBody FindCommentPageListReqVO findCommentPageListReqVO) {
return commentService.findCommentPageList(findCommentPageListReqVO);
}
} }

View File

@@ -9,6 +9,7 @@ import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
/** /**
@@ -104,12 +105,6 @@ public class CommentDO {
@TableField(value = "create_time") @TableField(value = "create_time")
private LocalDateTime createTime; private LocalDateTime createTime;
/**
* 下级评论总数
*/
@TableField(value = "child_comment_total")
private Long childCommentTotal;
/** /**
* 更新时间 * 更新时间
*/ */
@@ -117,7 +112,19 @@ public class CommentDO {
private LocalDateTime updateTime; private LocalDateTime updateTime;
/** /**
* 级评论的第一个回复的评论ID * 级评论总数(只有一级评论才需要统计)
*/
@TableField(value = "child_comment_total")
private Long childCommentTotal;
/**
* 评论热度
*/
@TableField(value = "heat")
private BigDecimal heat;
/**
* 最早回复的评论ID (只有一级评论需要)
*/ */
@TableField(value = "first_reply_comment_id") @TableField(value = "first_reply_comment_id")
private Long firstReplyCommentId; private Long firstReplyCommentId;

View File

@@ -0,0 +1,50 @@
package com.hanserwei.hannote.comment.biz.domain.dataobject;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 笔记计数表
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "t_note_count")
public class NoteCountDO {
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 笔记ID
*/
@TableField(value = "note_id")
private Long noteId;
/**
* 获得点赞总数
*/
@TableField(value = "like_total")
private Long likeTotal;
/**
* 获得收藏总数
*/
@TableField(value = "collect_total")
private Long collectTotal;
/**
* 被评论总数
*/
@TableField(value = "comment_total")
private Long commentTotal;
}

View File

@@ -11,7 +11,6 @@ import java.util.List;
@Mapper @Mapper
public interface CommentDOMapper extends BaseMapper<CommentDO> { public interface CommentDOMapper extends BaseMapper<CommentDO> {
/** /**
* 根据评论 ID 批量查询 * 根据评论 ID 批量查询
* *
@@ -55,4 +54,24 @@ public interface CommentDOMapper extends BaseMapper<CommentDO> {
*/ */
int updateFirstReplyCommentIdByPrimaryKey(@Param("firstReplyCommentId") Long firstReplyCommentId, int updateFirstReplyCommentIdByPrimaryKey(@Param("firstReplyCommentId") Long firstReplyCommentId,
@Param("id") Long id); @Param("id") Long id);
/**
* 查询评论分页数据
*
* @param noteId 笔记 ID
* @param offset 偏移量
* @param pageSize 页大小
* @return 评论分页数据
*/
List<CommentDO> selectPageList(@Param("noteId") Long noteId,
@Param("offset") long offset,
@Param("pageSize") long pageSize);
/**
* 批量查询二级评论
*
* @param commentIds 评论 ID 列表
* @return 二级评论
*/
List<CommentDO> selectTwoLevelCommentByIds(@Param("commentIds") List<Long> commentIds);
} }

View File

@@ -0,0 +1,17 @@
package com.hanserwei.hannote.comment.biz.domain.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hanserwei.hannote.comment.biz.domain.dataobject.NoteCountDO;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface NoteCountDOMapper extends BaseMapper<NoteCountDO> {
/**
* 查询笔记评论总数
*
* @param noteId 笔记ID
* @return 笔记评论总数
*/
Long selectCommentTotalByNoteId(Long noteId);
}

View File

@@ -0,0 +1,64 @@
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 FindCommentItemRspVO {
/**
* 评论 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 Long childCommentTotal;
/**
* 最早回复的评论
*/
private FindCommentItemRspVO firstReplyComment;
}

View File

@@ -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 FindCommentPageListReqVO {
@NotNull(message = "笔记 ID 不能为空")
private Long noteId;
@NotNull(message = "页码不能为空")
private Integer pageNo = 1;
}

View File

@@ -1,16 +1,21 @@
package com.hanserwei.hannote.comment.biz.rpc; package com.hanserwei.hannote.comment.biz.rpc;
import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.hanserwei.framework.common.constant.DateConstants; import com.hanserwei.framework.common.constant.DateConstants;
import com.hanserwei.framework.common.response.Response; import com.hanserwei.framework.common.response.Response;
import com.hanserwei.hannote.comment.biz.model.bo.CommentBO; import com.hanserwei.hannote.comment.biz.model.bo.CommentBO;
import com.hanserwei.hannote.kv.api.KeyValueFeignApi; import com.hanserwei.hannote.kv.api.KeyValueFeignApi;
import com.hanserwei.hannote.kv.dto.req.BatchAddCommentContentReqDTO; import com.hanserwei.hannote.kv.dto.req.BatchAddCommentContentReqDTO;
import com.hanserwei.hannote.kv.dto.req.BatchFindCommentContentReqDTO;
import com.hanserwei.hannote.kv.dto.req.CommentContentReqDTO; import com.hanserwei.hannote.kv.dto.req.CommentContentReqDTO;
import com.hanserwei.hannote.kv.dto.req.FindCommentContentReqDTO;
import com.hanserwei.hannote.kv.dto.resp.FindCommentContentRspDTO;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
import java.util.Objects;
@Component @Component
public class KeyValueRpcService { public class KeyValueRpcService {
@@ -54,4 +59,26 @@ public class KeyValueRpcService {
return true; return true;
} }
/**
* 批量查询评论内容
*
* @param noteId 笔记ID
* @param findCommentContentReqDTOS 查询参数
* @return 批量查询结果
*/
public List<FindCommentContentRspDTO> batchFindCommentContent(Long noteId, List<FindCommentContentReqDTO> findCommentContentReqDTOS) {
BatchFindCommentContentReqDTO bathFindCommentContentReqDTO = BatchFindCommentContentReqDTO.builder()
.noteId(noteId)
.commentContentKeys(findCommentContentReqDTOS)
.build();
Response<List<FindCommentContentRspDTO>> response = keyValueFeignApi.batchFindCommentContent(bathFindCommentContentReqDTO);
if (!response.isSuccess() || Objects.isNull(response.getData()) || CollUtil.isEmpty(response.getData())) {
return null;
}
return response.getData();
}
} }

View File

@@ -0,0 +1,45 @@
package com.hanserwei.hannote.comment.biz.rpc;
import cn.hutool.core.collection.CollUtil;
import com.hanserwei.framework.common.response.Response;
import com.hanserwei.hannote.user.api.UserFeignApi;
import com.hanserwei.hannote.user.dto.req.FindUsersByIdsReqDTO;
import com.hanserwei.hannote.user.dto.resp.FindUserByIdRspDTO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Component
public class UserRpcService {
@Resource
private UserFeignApi userFeignApi;
/**
* 批量查询用户信息
*
* @param userIds 用户 ID集合
* @return 用户信息集合
*/
public List<FindUserByIdRspDTO> findByIds(List<Long> userIds) {
if (CollUtil.isEmpty(userIds)) {
return null;
}
FindUsersByIdsReqDTO findUsersByIdsReqDTO = new FindUsersByIdsReqDTO();
// 去重, 并设置用户 ID 集合
findUsersByIdsReqDTO.setIds(userIds.stream().distinct().collect(Collectors.toList()));
Response<List<FindUserByIdRspDTO>> response = userFeignApi.findByIds(findUsersByIdsReqDTO);
if (!response.isSuccess() || Objects.isNull(response.getData()) || CollUtil.isEmpty(response.getData())) {
return null;
}
return response.getData();
}
}

View File

@@ -1,8 +1,11 @@
package com.hanserwei.hannote.comment.biz.service; package com.hanserwei.hannote.comment.biz.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.hanserwei.framework.common.response.PageResponse;
import com.hanserwei.framework.common.response.Response; import com.hanserwei.framework.common.response.Response;
import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentDO; 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.PublishCommentReqVO;
public interface CommentService extends IService<CommentDO> { public interface CommentService extends IService<CommentDO> {
@@ -13,4 +16,12 @@ public interface CommentService extends IService<CommentDO> {
* @return 响应 * @return 响应
*/ */
Response<?> publishComment(PublishCommentReqVO publishCommentReqVO); Response<?> publishComment(PublishCommentReqVO publishCommentReqVO);
/**
* 评论列表分页查询
*
* @param findCommentPageListReqVO 评论列表分页查询参数
* @return 响应
*/
PageResponse<FindCommentItemRspVO> findCommentPageList(FindCommentPageListReqVO findCommentPageListReqVO);
} }

View File

@@ -1,24 +1,41 @@
package com.hanserwei.hannote.comment.biz.service.impl; package com.hanserwei.hannote.comment.biz.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.hanserwei.framework.biz.context.holder.LoginUserContextHolder; import com.hanserwei.framework.biz.context.holder.LoginUserContextHolder;
import com.hanserwei.framework.common.constant.DateConstants;
import com.hanserwei.framework.common.response.PageResponse;
import com.hanserwei.framework.common.response.Response; import com.hanserwei.framework.common.response.Response;
import com.hanserwei.framework.common.utils.DateUtils;
import com.hanserwei.framework.common.utils.JsonUtils; import com.hanserwei.framework.common.utils.JsonUtils;
import com.hanserwei.hannote.comment.biz.constants.MQConstants; import com.hanserwei.hannote.comment.biz.constants.MQConstants;
import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentDO; import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentDO;
import com.hanserwei.hannote.comment.biz.domain.mapper.CommentDOMapper; import com.hanserwei.hannote.comment.biz.domain.mapper.CommentDOMapper;
import com.hanserwei.hannote.comment.biz.domain.mapper.NoteCountDOMapper;
import com.hanserwei.hannote.comment.biz.model.dto.PublishCommentMqDTO; 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.PublishCommentReqVO;
import com.hanserwei.hannote.comment.biz.retry.SendMqRetryHelper; import com.hanserwei.hannote.comment.biz.retry.SendMqRetryHelper;
import com.hanserwei.hannote.comment.biz.rpc.DistributedIdGeneratorRpcService; import com.hanserwei.hannote.comment.biz.rpc.DistributedIdGeneratorRpcService;
import com.hanserwei.hannote.comment.biz.rpc.KeyValueRpcService;
import com.hanserwei.hannote.comment.biz.rpc.UserRpcService;
import com.hanserwei.hannote.comment.biz.service.CommentService; import com.hanserwei.hannote.comment.biz.service.CommentService;
import com.hanserwei.hannote.kv.dto.req.FindCommentContentReqDTO;
import com.hanserwei.hannote.kv.dto.resp.FindCommentContentRspDTO;
import com.hanserwei.hannote.user.dto.resp.FindUserByIdRspDTO;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@Service @Service
@Slf4j @Slf4j
@@ -28,6 +45,14 @@ public class CommentServiceImpl extends ServiceImpl<CommentDOMapper, CommentDO>
private SendMqRetryHelper sendMqRetryHelper; private SendMqRetryHelper sendMqRetryHelper;
@Resource @Resource
private DistributedIdGeneratorRpcService distributedIdGeneratorRpcService; private DistributedIdGeneratorRpcService distributedIdGeneratorRpcService;
@Resource
private NoteCountDOMapper noteCountDOMapper;
@Resource
private CommentDOMapper commentDOMapper;
@Resource
private KeyValueRpcService keyValueRpcService;
@Resource
private UserRpcService userRpcService;
@Override @Override
public Response<?> publishComment(PublishCommentReqVO publishCommentReqVO) { public Response<?> publishComment(PublishCommentReqVO publishCommentReqVO) {
@@ -61,4 +86,171 @@ public class CommentServiceImpl extends ServiceImpl<CommentDOMapper, CommentDO>
sendMqRetryHelper.asyncSend(MQConstants.TOPIC_PUBLISH_COMMENT, JsonUtils.toJsonString(publishCommentMqDTO)); sendMqRetryHelper.asyncSend(MQConstants.TOPIC_PUBLISH_COMMENT, JsonUtils.toJsonString(publishCommentMqDTO));
return Response.success(); return Response.success();
} }
/**
* 设置评论内容
*
* @param commentUuidAndContentMap 评论内容
* @param commentDO 评论DO
* @param firstReplyCommentRspVO 一级评论
*/
private static void setCommentContent(Map<String, String> commentUuidAndContentMap, CommentDO commentDO, FindCommentItemRspVO firstReplyCommentRspVO) {
if (CollUtil.isNotEmpty(commentUuidAndContentMap)) {
String contentUuid = commentDO.getContentUuid();
if (StringUtils.isNotBlank(contentUuid)) {
firstReplyCommentRspVO.setContent(commentUuidAndContentMap.get(contentUuid));
}
}
}
/**
* 设置用户信息
*
* @param userIdAndDTOMap 用户信息
* @param userId 用户ID
* @param oneLevelCommentRspVO 一级评论
*/
private static void setUserInfo(Map<Long, FindUserByIdRspDTO> userIdAndDTOMap, Long userId, FindCommentItemRspVO oneLevelCommentRspVO) {
FindUserByIdRspDTO findUserByIdRspDTO = userIdAndDTOMap.get(userId);
if (Objects.nonNull(findUserByIdRspDTO)) {
oneLevelCommentRspVO.setAvatar(findUserByIdRspDTO.getAvatar());
oneLevelCommentRspVO.setNickname(findUserByIdRspDTO.getNickName());
}
}
@Override
public PageResponse<FindCommentItemRspVO> findCommentPageList(FindCommentPageListReqVO findCommentPageListReqVO) {
// 笔记ID
Long noteId = findCommentPageListReqVO.getNoteId();
//当前页码
Integer pageNo = findCommentPageListReqVO.getPageNo();
// 每页展示一级评论数量
int pageSize = 10;
// TODO 先从缓存中查询
// 查询评论总数
Long count = noteCountDOMapper.selectCommentTotalByNoteId(noteId);
if (Objects.isNull(count)) {
return PageResponse.success(null, pageNo, pageSize);
}
// 分页返回参数
List<FindCommentItemRspVO> commentRspVOS = null;
// 若评论总数大于0
if (count > 0) {
commentRspVOS = Lists.newArrayList();
// 计算分页查询的offset
long offset = PageResponse.getOffset(pageNo, pageSize);
//查询一级评论
List<CommentDO> oneLevelCommentIds = commentDOMapper.selectPageList(noteId, offset, pageSize);
// 过滤出所有最早回复的二级评论ID
List<Long> twoLevelCommentIds = oneLevelCommentIds.stream()
.map(CommentDO::getFirstReplyCommentId)
.filter(e -> e != 0)
.toList();
// 查询二级评论
Map<Long, CommentDO> commentIdAndDOMap = null;
List<CommentDO> twoLevelCommentDOS = null;
if (CollUtil.isNotEmpty(twoLevelCommentIds)) {
twoLevelCommentDOS = commentDOMapper.selectTwoLevelCommentByIds(twoLevelCommentIds);
// 转Map方便后续数据拼接
commentIdAndDOMap = twoLevelCommentDOS.stream()
.collect(Collectors.toMap(CommentDO::getId, e -> e));
}
// 调用KV服务需要的入参
List<FindCommentContentReqDTO> findCommentContentReqDTOS = Lists.newArrayList();
// 调用用户服务需要的入参
List<Long> userIds = Lists.newArrayList();
// 一二级评论合并到一起
List<CommentDO> allCommentDOS = Lists.newArrayList();
CollUtil.addAll(allCommentDOS, oneLevelCommentIds);
CollUtil.addAll(allCommentDOS, twoLevelCommentDOS);
// 循环提取RPC需要的入参数据
allCommentDOS.forEach(commentDO -> {
// 构建KV服务批量查询评论内容的入参
boolean isContentEmpty = commentDO.getIsContentEmpty();
if (!isContentEmpty) {
FindCommentContentReqDTO findCommentContentReqDTO = FindCommentContentReqDTO.builder()
.contentId(commentDO.getContentUuid())
.yearMonth(DateConstants.DATE_FORMAT_Y_M.format(commentDO.getCreateTime()))
.build();
findCommentContentReqDTOS.add(findCommentContentReqDTO);
}
// 构建用户服务批量查询用户信息的入参
userIds.add(commentDO.getUserId());
});
// 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);
// 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 commentDO : oneLevelCommentIds) {
// 一级评论
Long userId = commentDO.getUserId();
FindCommentItemRspVO oneLevelCommentRspVO = FindCommentItemRspVO.builder()
.userId(userId)
.commentId(commentDO.getId())
.imageUrl(commentDO.getImageUrl())
.createTime(DateUtils.formatRelativeTime(commentDO.getCreateTime()))
.likeTotal(commentDO.getLikeTotal())
.childCommentTotal(commentDO.getChildCommentTotal())
.build();
// 用户信息
if (userIdAndDTOMap != null) {
setUserInfo(userIdAndDTOMap, userId, oneLevelCommentRspVO);
}
// 笔记内容
setCommentContent(commentUuidAndContentMap, commentDO, oneLevelCommentRspVO);
// 二级评论
Long firstReplyCommentId = commentDO.getFirstReplyCommentId();
if (CollUtil.isNotEmpty(commentIdAndDOMap)) {
CommentDO firstReplyCommentDO = commentIdAndDOMap.get(firstReplyCommentId);
if (Objects.nonNull(firstReplyCommentDO)) {
Long firstReplyCommentUserId = firstReplyCommentDO.getUserId();
FindCommentItemRspVO firstReplyCommentRspVO = FindCommentItemRspVO.builder()
.userId(firstReplyCommentDO.getUserId())
.commentId(firstReplyCommentDO.getId())
.imageUrl(firstReplyCommentDO.getImageUrl())
.createTime(DateUtils.formatRelativeTime(firstReplyCommentDO.getCreateTime()))
.likeTotal(firstReplyCommentDO.getLikeTotal())
.build();
if (userIdAndDTOMap != null) {
setUserInfo(userIdAndDTOMap, firstReplyCommentUserId, firstReplyCommentRspVO);
}
// 用户信息
oneLevelCommentRspVO.setFirstReplyComment(firstReplyCommentRspVO);
// 笔记内容
setCommentContent(commentUuidAndContentMap, firstReplyCommentDO, firstReplyCommentRspVO);
}
}
commentRspVOS.add(oneLevelCommentRspVO);
}
// TODO 后续逻辑
}
return PageResponse.success(commentRspVOS, pageNo, count, pageSize);
}
} }

View File

@@ -20,6 +20,7 @@
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" /> <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" /> <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
<result column="child_comment_total" jdbcType="BIGINT" property="childCommentTotal"/> <result column="child_comment_total" jdbcType="BIGINT" property="childCommentTotal"/>
<result column="heat" jdbcType="DECIMAL" property="heat"/>
<result column="first_reply_comment_id" jdbcType="BIGINT" property="firstReplyCommentId"/> <result column="first_reply_comment_id" jdbcType="BIGINT" property="firstReplyCommentId"/>
</resultMap> </resultMap>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
@@ -40,10 +41,11 @@
create_time, create_time,
update_time, update_time,
child_comment_total, child_comment_total,
heat,
first_reply_comment_id first_reply_comment_id
</sql> </sql>
<select id="selectByCommentIds" resultMap="BaseResultMap" parameterType="list"> <select id="selectByCommentIds" parameterType="list" resultMap="BaseResultMap">
select id, select id,
level, level,
parent_id, parent_id,
@@ -53,7 +55,7 @@
first_reply_comment_id first_reply_comment_id
from t_comment from t_comment
where id in where id in
<foreach collection="commentIds" open="(" separator="," close=")" item="commentId"> <foreach close=")" collection="commentIds" item="commentId" open="(" separator=",">
#{commentId} #{commentId}
</foreach> </foreach>
</select> </select>
@@ -81,12 +83,12 @@
</foreach> </foreach>
ELSE heat END ELSE heat END
WHERE id IN WHERE id IN
<foreach collection="commentIds" item="commentId" open="(" close=")" separator=","> <foreach close=")" collection="commentIds" item="commentId" open="(" separator=",">
#{commentId} #{commentId}
</foreach> </foreach>
</update> </update>
<select id="selectEarliestByParentId" resultMap="BaseResultMap" parameterType="map"> <select id="selectEarliestByParentId" parameterType="map" resultMap="BaseResultMap">
select id select id
from t_comment from t_comment
where parent_id = #{parentId} where parent_id = #{parentId}
@@ -100,4 +102,37 @@
set first_reply_comment_id = #{firstReplyCommentId} set first_reply_comment_id = #{firstReplyCommentId}
where id = #{id} where id = #{id}
</update> </update>
<select id="selectPageList" resultMap="BaseResultMap" parameterType="map">
select id,
user_id,
content_uuid,
is_content_empty,
image_url,
like_total,
is_top,
create_time,
first_reply_comment_id,
child_comment_total
from t_comment
where note_id = #{noteId}
and level = 1
order by heat desc
limit #{offset}, #{pageSize}
</select>
<select id="selectTwoLevelCommentByIds" resultMap="BaseResultMap" parameterType="list">
select id,
user_id,
content_uuid,
is_content_empty,
image_url,
like_total,
create_time
from t_comment
where id in
<foreach collection="commentIds" open="(" separator="," close=")" item="commentId">
#{commentId}
</foreach>
</select>
</mapper> </mapper>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hanserwei.hannote.comment.biz.domain.mapper.NoteCountDOMapper">
<resultMap id="BaseResultMap" type="com.hanserwei.hannote.comment.biz.domain.dataobject.NoteCountDO">
<!--@mbg.generated-->
<!--@Table t_note_count-->
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="note_id" jdbcType="BIGINT" property="noteId"/>
<result column="like_total" jdbcType="BIGINT" property="likeTotal"/>
<result column="collect_total" jdbcType="BIGINT" property="collectTotal"/>
<result column="comment_total" jdbcType="BIGINT" property="commentTotal"/>
</resultMap>
<sql id="Base_Column_List">
<!--@mbg.generated-->
id, note_id, like_total, collect_total, comment_total
</sql>
<select id="selectCommentTotalByNoteId" resultType="long">
select comment_total
from t_note_count
where note_id = #{noteId}
</select>
</mapper>

View File

@@ -7,7 +7,6 @@ import org.apache.ibatis.annotations.Param;
@Mapper @Mapper
public interface NoteCountDOMapper extends BaseMapper<NoteCountDO> { public interface NoteCountDOMapper extends BaseMapper<NoteCountDO> {
/** /**
* 添加笔记计数记录或更新笔记点赞数 * 添加笔记计数记录或更新笔记点赞数
* *

View File

@@ -2,15 +2,15 @@ package com.hanserwei.hannote.kv.api;
import com.hanserwei.framework.common.response.Response; import com.hanserwei.framework.common.response.Response;
import com.hanserwei.hannote.kv.constant.ApiConstants; import com.hanserwei.hannote.kv.constant.ApiConstants;
import com.hanserwei.hannote.kv.dto.req.AddNoteContentReqDTO; import com.hanserwei.hannote.kv.dto.req.*;
import com.hanserwei.hannote.kv.dto.req.BatchAddCommentContentReqDTO; import com.hanserwei.hannote.kv.dto.resp.FindCommentContentRspDTO;
import com.hanserwei.hannote.kv.dto.req.DeleteNoteContentReqDTO;
import com.hanserwei.hannote.kv.dto.req.FindNoteContentReqDTO;
import com.hanserwei.hannote.kv.dto.resp.FindNoteContentRspDTO; import com.hanserwei.hannote.kv.dto.resp.FindNoteContentRspDTO;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
@FeignClient(name = ApiConstants.SERVICE_NAME) @FeignClient(name = ApiConstants.SERVICE_NAME)
public interface KeyValueFeignApi { public interface KeyValueFeignApi {
@@ -28,4 +28,7 @@ public interface KeyValueFeignApi {
@PostMapping(value = PREFIX + "/comment/content/batchAdd") @PostMapping(value = PREFIX + "/comment/content/batchAdd")
Response<?> batchAddCommentContent(@RequestBody BatchAddCommentContentReqDTO batchAddCommentContentReqDTO); Response<?> batchAddCommentContent(@RequestBody BatchAddCommentContentReqDTO batchAddCommentContentReqDTO);
@PostMapping(value = PREFIX + "/comment/content/batchFind")
Response<List<FindCommentContentRspDTO>> batchFindCommentContent(@RequestBody BatchFindCommentContentReqDTO batchFindCommentContentReqDTO);
} }

View File

@@ -347,3 +347,12 @@ Content-Type: application/json
} }
] ]
} }
### 分页查询评论
POST http://localhost:8093/comment/list
Content-Type: application/json
{
"noteId": 1862481582414102549,
"pageNo": 1
}