From 9ec330216f5ccf7b948dd7ba3ab5e547388c172b Mon Sep 17 00:00:00 2001 From: Hanserwei <2628273921@qq.com> Date: Fri, 7 Nov 2025 17:42:43 +0800 Subject: [PATCH] =?UTF-8?q?feat(count):=20=E5=AE=9E=E7=8E=B0=E8=AF=84?= =?UTF-8?q?=E8=AE=BA=E8=AE=A1=E6=95=B0=E5=8A=9F=E8=83=BD=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E4=BA=8C=E7=BA=A7=E8=AF=84=E8=AE=BA=E7=BB=9F=E8=AE=A1=20-=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=AF=84=E8=AE=BA=E6=95=B0=E6=8D=AE=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=20CommentDO=20=E5=8F=8A=E5=85=B6=20MyBatis=20?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E9=85=8D=E7=BD=AE=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=AF=84=E8=AE=BA=E7=BA=A7=E5=88=AB=E6=9E=9A=E4=B8=BE=20Commen?= =?UTF-8?q?tLevelEnum=20=E5=8C=BA=E5=88=86=E4=B8=80=E7=BA=A7=E4=B8=8E?= =?UTF-8?q?=E4=BA=8C=E7=BA=A7=E8=AF=84=E8=AE=BA=20-=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20CountNoteChildCommentConsumer=20=E6=B6=88=E8=B4=B9=20MQ=20?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=B9=B6=E6=9B=B4=E6=96=B0=E5=AD=90=E8=AF=84?= =?UTF-8?q?=E8=AE=BA=E6=80=BB=E6=95=B0=20-=20=E4=BF=AE=E6=94=B9=20CountPub?= =?UTF-8?q?lishCommentMqDTO=20=E5=A2=9E=E5=8A=A0=20level=20=E5=92=8C=20par?= =?UTF-8?q?entId=20=E5=AD=97=E6=AE=B5=E4=BB=A5=E6=94=AF=E6=8C=81=E5=B1=82?= =?UTF-8?q?=E7=BA=A7=E8=AF=86=E5=88=AB=20-=20=E8=B0=83=E6=95=B4=20Comment2?= =?UTF-8?q?DBConsumer=20=E4=B8=AD=E6=9E=84=E9=80=A0=20CountPublishCommentM?= =?UTF-8?q?qDTO=20=E7=9A=84=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=20commentBO=20=E6=8F=90=E5=8F=96=E5=AE=8C=E6=95=B4=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=20-=20=E9=85=8D=E7=BD=AE=20MyBatis=20Code=20Helper=20?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E6=8C=87=E5=90=91=E6=96=B0=E7=9A=84=20han-no?= =?UTF-8?q?te-count=20=E6=A8=A1=E5=9D=97=E8=B7=AF=E5=BE=84=20-=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=20gateApi.http=20=E6=B5=8B=E8=AF=95=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B=EF=BC=8C=E6=B7=BB=E5=8A=A0=20replyCommentId?= =?UTF-8?q?=20=E5=8F=82=E6=95=B0=E7=94=A8=E4=BA=8E=E6=A8=A1=E6=8B=9F?= =?UTF-8?q?=E4=BA=8C=E7=BA=A7=E8=AF=84=E8=AE=BA=E5=8F=91=E5=B8=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/MyBatisCodeHelperDatasource.xml | 16 ++- .../biz/consumer/Comment2DBConsumer.java | 10 +- .../model/dto/CountPublishCommentMqDTO.java | 10 ++ .../CountNoteChildCommentConsumer.java | 80 ++++++++++++ .../biz/domain/dataobject/CommentDO.java | 118 ++++++++++++++++++ .../biz/domain/mapper/CommentDOMapper.java | 19 +++ .../count/biz/enums/CommentLevelEnum.java | 17 +++ .../model/dto/CountPublishCommentMqDTO.java | 10 ++ .../resources/mapperxml/CommentDOMapper.xml | 51 ++++++++ http-client/gateApi.http | 5 +- 10 files changed, 321 insertions(+), 15 deletions(-) create mode 100644 han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/consumer/CountNoteChildCommentConsumer.java create mode 100644 han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/domain/dataobject/CommentDO.java create mode 100644 han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/domain/mapper/CommentDOMapper.java create mode 100644 han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/enums/CommentLevelEnum.java create mode 100644 han-note-count/han-note-count-biz/src/main/resources/mapperxml/CommentDOMapper.xml diff --git a/.idea/MyBatisCodeHelperDatasource.xml b/.idea/MyBatisCodeHelperDatasource.xml index efe123d..78337bc 100644 --- a/.idea/MyBatisCodeHelperDatasource.xml +++ b/.idea/MyBatisCodeHelperDatasource.xml @@ -7,15 +7,13 @@ diff --git a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/consumer/Comment2DBConsumer.java b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/consumer/Comment2DBConsumer.java index 2880692..9f569dd 100644 --- a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/consumer/Comment2DBConsumer.java +++ b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/consumer/Comment2DBConsumer.java @@ -197,10 +197,12 @@ public class Comment2DBConsumer { // 如果批量插入的行数大于 0 if (Objects.nonNull(insertedRows) && insertedRows > 0) { // 构建发送给计数服务的 DTO 集合 - List countPublishCommentMqDTOS = publishCommentMqDTOS.stream() - .map(publishCommentMqDTO -> CountPublishCommentMqDTO.builder() - .noteId(publishCommentMqDTO.getNoteId()) - .commentId(publishCommentMqDTO.getCommentId()) + List countPublishCommentMqDTOS = commentBOS.stream() + .map(commentBO -> CountPublishCommentMqDTO.builder() + .noteId(commentBO.getNoteId()) + .commentId(commentBO.getId()) + .level(commentBO.getLevel()) + .parentId(commentBO.getParentId()) .build()) .toList(); diff --git a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/model/dto/CountPublishCommentMqDTO.java b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/model/dto/CountPublishCommentMqDTO.java index bab5628..940eac2 100644 --- a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/model/dto/CountPublishCommentMqDTO.java +++ b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/model/dto/CountPublishCommentMqDTO.java @@ -21,4 +21,14 @@ public class CountPublishCommentMqDTO { */ private Long commentId; + /** + * 评论级别 + */ + private Integer level; + + /** + * 父 ID + */ + private Long parentId; + } \ No newline at end of file diff --git a/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/consumer/CountNoteChildCommentConsumer.java b/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/consumer/CountNoteChildCommentConsumer.java new file mode 100644 index 0000000..46b7f4d --- /dev/null +++ b/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/consumer/CountNoteChildCommentConsumer.java @@ -0,0 +1,80 @@ +package com.hanserwei.hannote.count.biz.consumer; + +import cn.hutool.core.collection.CollUtil; +import com.github.phantomthief.collection.BufferTrigger; +import com.google.common.collect.Lists; +import com.hanserwei.framework.common.utils.JsonUtils; +import com.hanserwei.hannote.count.biz.constant.MQConstants; +import com.hanserwei.hannote.count.biz.domain.mapper.CommentDOMapper; +import com.hanserwei.hannote.count.biz.enums.CommentLevelEnum; +import com.hanserwei.hannote.count.biz.model.dto.CountPublishCommentMqDTO; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; +import org.apache.rocketmq.spring.core.RocketMQListener; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +@Component +@RocketMQMessageListener(consumerGroup = "han_note_group_child_comment_total" + MQConstants.TOPIC_COUNT_NOTE_COMMENT, // Group 组 + topic = MQConstants.TOPIC_COUNT_NOTE_COMMENT // 主题 Topic +) +@Slf4j +public class CountNoteChildCommentConsumer implements RocketMQListener { + + @Resource + private CommentDOMapper commentDOMapper; + + private final BufferTrigger bufferTrigger = BufferTrigger.batchBlocking() + .bufferSize(50000) // 缓存队列的最大容量 + .batchSize(1000) // 一批次最多聚合 1000 条 + .linger(Duration.ofSeconds(1)) // 多久聚合一次(1s 一次) + .setConsumerEx(this::consumeMessage) // 设置消费者方法 + .build(); + + @Override + public void onMessage(String body) { + // 往 bufferTrigger 中添加元素 + bufferTrigger.enqueue(body); + } + + private void consumeMessage(List bodys) { + log.info("==> 【笔记二级评论数】聚合消息, size: {}", bodys.size()); + log.info("==> 【笔记二级评论数】聚合消息, {}", JsonUtils.toJsonString(bodys)); + + // 将聚合后的消息体 Json 转 List + List countPublishCommentMqDTOList = Lists.newArrayList(); + bodys.forEach(body -> { + try { + List list = JsonUtils.parseList(body, CountPublishCommentMqDTO.class); + countPublishCommentMqDTOList.addAll(list); + } catch (Exception e) { + log.error("", e); + } + }); + + // 过滤出二级评论,并按 parent_id 分组 + Map> groupMap = countPublishCommentMqDTOList.stream() + .filter(commentMqDTO -> Objects.equals(CommentLevelEnum.TWO.getCode(), commentMqDTO.getLevel())) + .collect(Collectors.groupingBy(CountPublishCommentMqDTO::getParentId)); // 按 parent_id 分组 + + // 若无二级评论,则直接 return + if (CollUtil.isEmpty(groupMap)) return; + + // 循环分组字典 + for (Map.Entry> entry : groupMap.entrySet()) { + // 一级评论 ID + Long parentId = entry.getKey(); + // 评论数 + int count = CollUtil.size(entry.getValue()); + + // 更新一级评论的下级评论总数,进行累加操作 + commentDOMapper.updateChildCommentTotal(parentId, count); + } + } +} \ No newline at end of file diff --git a/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/domain/dataobject/CommentDO.java b/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/domain/dataobject/CommentDO.java new file mode 100644 index 0000000..7ca6daa --- /dev/null +++ b/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/domain/dataobject/CommentDO.java @@ -0,0 +1,118 @@ +package com.hanserwei.hannote.count.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; + +import java.time.LocalDateTime; + +/** + * 评论表 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@TableName(value = "t_comment") +public class CommentDO { + /** + * id + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 关联的笔记ID + */ + @TableField(value = "note_id") + private Long noteId; + + /** + * 发布者用户ID + */ + @TableField(value = "user_id") + private Long userId; + + /** + * 评论内容UUID + */ + @TableField(value = "content_uuid") + private String contentUuid; + + /** + * 内容是否为空(0:不为空 1:为空) + */ + @TableField(value = "is_content_empty") + private Boolean isContentEmpty; + + /** + * 评论附加图片URL + */ + @TableField(value = "image_url") + private String imageUrl; + + /** + * 级别(1:一级评论 2:二级评论) + */ + @TableField(value = "`level`") + private Integer level; + + /** + * 评论被回复次数,仅一级评论需要 + */ + @TableField(value = "reply_total") + private Long replyTotal; + + /** + * 评论被点赞次数 + */ + @TableField(value = "like_total") + private Long likeTotal; + + /** + * 父ID (若是对笔记的评论,则此字段存储笔记ID; 若是二级评论,则此字段存储一级评论的ID) + */ + @TableField(value = "parent_id") + private Long parentId; + + /** + * 回复哪个的评论 (0表示是对笔记的评论,若是对他人评论的回复,则存储回复评论的ID) + */ + @TableField(value = "reply_comment_id") + private Long replyCommentId; + + /** + * 回复的哪个用户, 存储用户ID + */ + @TableField(value = "reply_user_id") + private Long replyUserId; + + /** + * 是否置顶(0:不置顶 1:置顶) + */ + @TableField(value = "is_top") + private Boolean isTop; + + /** + * 创建时间 + */ + @TableField(value = "create_time") + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @TableField(value = "update_time") + private LocalDateTime updateTime; + + /** + * 二级评论总数(只有一级评论才需要统计) + */ + @TableField(value = "child_comment_total") + private Long childCommentTotal; +} \ No newline at end of file diff --git a/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/domain/mapper/CommentDOMapper.java b/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/domain/mapper/CommentDOMapper.java new file mode 100644 index 0000000..5acd9fa --- /dev/null +++ b/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/domain/mapper/CommentDOMapper.java @@ -0,0 +1,19 @@ +package com.hanserwei.hannote.count.biz.domain.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.hanserwei.hannote.count.biz.domain.dataobject.CommentDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface CommentDOMapper extends BaseMapper { + + /** + * 更新一级评论的子评论总数 + * + * @param parentId 一级评论 ID + * @param count 子评论数 + * @return 更新结果 + */ + int updateChildCommentTotal(@Param("parentId") Long parentId, @Param("count") int count); +} \ No newline at end of file diff --git a/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/enums/CommentLevelEnum.java b/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/enums/CommentLevelEnum.java new file mode 100644 index 0000000..607bd25 --- /dev/null +++ b/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/enums/CommentLevelEnum.java @@ -0,0 +1,17 @@ +package com.hanserwei.hannote.count.biz.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum CommentLevelEnum { + // 一级评论 + ONE(1), + // 二级评论 + TWO(2), + ; + + private final Integer code; + +} \ No newline at end of file diff --git a/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/model/dto/CountPublishCommentMqDTO.java b/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/model/dto/CountPublishCommentMqDTO.java index c79ae7b..ea6c20d 100644 --- a/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/model/dto/CountPublishCommentMqDTO.java +++ b/han-note-count/han-note-count-biz/src/main/java/com/hanserwei/hannote/count/biz/model/dto/CountPublishCommentMqDTO.java @@ -21,4 +21,14 @@ public class CountPublishCommentMqDTO { */ private Long commentId; + /** + * 评论级别 + */ + private Integer level; + + /** + * 父 ID + */ + private Long parentId; + } \ No newline at end of file diff --git a/han-note-count/han-note-count-biz/src/main/resources/mapperxml/CommentDOMapper.xml b/han-note-count/han-note-count-biz/src/main/resources/mapperxml/CommentDOMapper.xml new file mode 100644 index 0000000..e1074e1 --- /dev/null +++ b/han-note-count/han-note-count-biz/src/main/resources/mapperxml/CommentDOMapper.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + id, + note_id, + user_id, + content_uuid, + is_content_empty, + image_url, + `level`, + reply_total, + like_total, + parent_id, + reply_comment_id, + reply_user_id, + is_top, + create_time, + update_time, + child_comment_total + + + + update t_comment + set child_comment_total = child_comment_total + #{count}, + update_time = now() + where id = #{parentId} + and level = 1 + + \ No newline at end of file diff --git a/http-client/gateApi.http b/http-client/gateApi.http index d91cf32..9fce570 100644 --- a/http-client/gateApi.http +++ b/http-client/gateApi.http @@ -298,8 +298,9 @@ Authorization: Bearer {{token}} { "noteId": 1862481582414102549, - "content": "这是一条测试评论计数的评论111", - "imageUrl": "https://cdn.pixabay.com/photo/2025/10/05/15/06/autumn-9875155_1280.jpg" + "content": "这是一条测试评论计数的二级评论333", + "imageUrl": "https://cdn.pixabay.com/photo/2025/10/05/15/06/autumn-9875155_1280.jpg", + "replyCommentId": 4002 } ### 批量添加评论