From c454e1832cde9c643d4d1aac4445c3171966c80b Mon Sep 17 00:00:00 2001
From: Hanserwei <2628273921@qq.com>
Date: Fri, 7 Nov 2025 21:19:42 +0800
Subject: [PATCH] =?UTF-8?q?feat(comment):=20=E6=96=B0=E5=A2=9E=E8=AF=84?=
=?UTF-8?q?=E8=AE=BA=E7=83=AD=E5=BA=A6=E8=AE=A1=E7=AE=97=E4=B8=8E=E6=9B=B4?=
=?UTF-8?q?=E6=96=B0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在评论数据对象中新增 childCommentTotal 和 heat 字段
- 扩展 CommentDOMapper 支持批量更新评论热度值
- 新增 CommentHeatBO 类用于封装评论热度信息
- 实现基于点赞数和回复数的热度值计算工具类 HeatCalculator
- 添加 RocketMQ 消费者异步处理评论热度更新消息
- 引入 buffer-trigger依赖实现消息聚合发送
- 扩展 JsonUtils 工具类支持 Set 类型反序列化
- 新增 MQ 常量 TOPIC_COMMENT_HEAT_UPDATE用于热度更新主题
- 修改 SQL 脚本增加 heat 字段并设置默认值- 更新测试接口请求参数内容以适配新逻辑
---
han-note-comment/han-note-comment-biz/pom.xml | 6 ++
.../comment/biz/constants/MQConstants.java | 5 ++
.../consumer/CommentHeatUpdateConsumer.java | 90 +++++++++++++++++++
.../biz/domain/dataobject/CommentDO.java | 6 ++
.../biz/domain/mapper/CommentDOMapper.java | 11 +++
.../comment/biz/model/bo/CommentHeatBO.java | 22 +++++
.../comment/biz/utils/HeatCalculator.java | 40 +++++++++
.../resources/mapperxml/CommentDOMapper.xml | 38 +++++++-
.../count/biz/constant/MQConstants.java | 5 ++
.../CountNoteChildCommentConsumer.java | 28 ++++++
.../framework/common/utils/JsonUtils.java | 20 +++++
http-client/gateApi.http | 2 +-
sql/createTable.sql | 4 +
13 files changed, 272 insertions(+), 5 deletions(-)
create mode 100644 han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/consumer/CommentHeatUpdateConsumer.java
create mode 100644 han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/model/bo/CommentHeatBO.java
create mode 100644 han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/utils/HeatCalculator.java
diff --git a/han-note-comment/han-note-comment-biz/pom.xml b/han-note-comment/han-note-comment-biz/pom.xml
index a229522..96ffe1e 100644
--- a/han-note-comment/han-note-comment-biz/pom.xml
+++ b/han-note-comment/han-note-comment-biz/pom.xml
@@ -113,6 +113,12 @@
han-note-kv-api
+
+
+ com.github.phantomthief
+ buffer-trigger
+
+
diff --git a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/constants/MQConstants.java b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/constants/MQConstants.java
index cd39c26..85628d4 100644
--- a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/constants/MQConstants.java
+++ b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/constants/MQConstants.java
@@ -12,4 +12,9 @@ public interface MQConstants {
*/
String TOPIC_COUNT_NOTE_COMMENT = "CountNoteCommentTopic";
+ /**
+ * Topic: 评论热度值更新
+ */
+ String TOPIC_COMMENT_HEAT_UPDATE = "CommentHeatUpdateTopic";
+
}
\ No newline at end of file
diff --git a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/consumer/CommentHeatUpdateConsumer.java b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/consumer/CommentHeatUpdateConsumer.java
new file mode 100644
index 0000000..65a8ea4
--- /dev/null
+++ b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/consumer/CommentHeatUpdateConsumer.java
@@ -0,0 +1,90 @@
+package com.hanserwei.hannote.comment.biz.consumer;
+
+import com.github.phantomthief.collection.BufferTrigger;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.hanserwei.framework.common.utils.JsonUtils;
+import com.hanserwei.hannote.comment.biz.constants.MQConstants;
+import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentDO;
+import com.hanserwei.hannote.comment.biz.domain.mapper.CommentDOMapper;
+import com.hanserwei.hannote.comment.biz.model.bo.CommentHeatBO;
+import com.hanserwei.hannote.comment.biz.utils.HeatCalculator;
+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.math.BigDecimal;
+import java.time.Duration;
+import java.util.List;
+import java.util.Set;
+
+@Component
+@RocketMQMessageListener(consumerGroup = "han_note_group_" + MQConstants.TOPIC_COMMENT_HEAT_UPDATE, // Group 组
+ topic = MQConstants.TOPIC_COMMENT_HEAT_UPDATE // 主题 Topic
+)
+@Slf4j
+public class CommentHeatUpdateConsumer implements RocketMQListener {
+
+ @Resource
+ private CommentDOMapper commentDOMapper;
+
+ private final BufferTrigger bufferTrigger = BufferTrigger.batchBlocking()
+ .bufferSize(50000) // 缓存队列的最大容量
+ .batchSize(300) // 一批次最多聚合 300 条
+ .linger(Duration.ofSeconds(2)) // 多久聚合一次(2s 一次)
+ .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 转 Set, 去重相同的评论 ID, 防止重复计算
+ Set commentIds = Sets.newHashSet();
+ bodys.forEach(body -> {
+ try {
+ Set list = JsonUtils.parseSet(body, Long.class);
+ commentIds.addAll(list);
+ } catch (Exception e) {
+ log.error("", e);
+ }
+ });
+
+ log.info("==> 去重后的评论 ID: {}", commentIds);
+
+ // 批量查询评论
+ List commentDOS = commentDOMapper.selectByCommentIds(commentIds.stream().toList());
+
+ // 评论 ID
+ List ids = Lists.newArrayList();
+ // 热度值 BO
+ List commentBOS = Lists.newArrayList();
+
+ //重新计算每条评论的热度值
+ commentDOS.forEach(commentDO -> {
+ Long commentId = commentDO.getId();
+ // 被点赞数
+ Long likeTotal = commentDO.getLikeTotal();
+ // 被回复数
+ Long childCommentTotal = commentDO.getChildCommentTotal();
+
+ // 计算热度值
+ BigDecimal heatNum = HeatCalculator.calculateHeat(likeTotal, childCommentTotal);
+ ids.add(commentId);
+ commentBOS.add(CommentHeatBO.builder()
+ .id(commentId)
+ .heat(heatNum.doubleValue())
+ .build());
+ });
+ // 批量更新评论热度值
+ commentDOMapper.batchUpdateHeatByCommentIds(ids, commentBOS);
+ }
+}
\ No newline at end of file
diff --git a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/dataobject/CommentDO.java b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/dataobject/CommentDO.java
index 36650aa..ef05284 100644
--- a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/dataobject/CommentDO.java
+++ b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/dataobject/CommentDO.java
@@ -104,6 +104,12 @@ public class CommentDO {
@TableField(value = "create_time")
private LocalDateTime createTime;
+ /**
+ * 下级评论总数
+ */
+ @TableField(value = "child_comment_total")
+ private Long childCommentTotal;
+
/**
* 更新时间
*/
diff --git a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/mapper/CommentDOMapper.java b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/mapper/CommentDOMapper.java
index 3e2d1be..9c09da1 100644
--- a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/mapper/CommentDOMapper.java
+++ b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/domain/mapper/CommentDOMapper.java
@@ -3,6 +3,7 @@ package com.hanserwei.hannote.comment.biz.domain.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentDO;
import com.hanserwei.hannote.comment.biz.model.bo.CommentBO;
+import com.hanserwei.hannote.comment.biz.model.bo.CommentHeatBO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@@ -26,4 +27,14 @@ public interface CommentDOMapper extends BaseMapper {
* @return 插入数量
*/
int batchInsert(@Param("comments") List comments);
+
+ /**
+ * 批量更新热度值
+ *
+ * @param commentIds 评论 ID 列表
+ * @param commentHeatBOS 热度值列表
+ * @return 更新数量
+ */
+ int batchUpdateHeatByCommentIds(@Param("commentIds") List commentIds,
+ @Param("commentHeatBOS") List commentHeatBOS);
}
\ No newline at end of file
diff --git a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/model/bo/CommentHeatBO.java b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/model/bo/CommentHeatBO.java
new file mode 100644
index 0000000..6cf0458
--- /dev/null
+++ b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/model/bo/CommentHeatBO.java
@@ -0,0 +1,22 @@
+package com.hanserwei.hannote.comment.biz.model.bo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class CommentHeatBO {
+ /**
+ * 评论 ID
+ */
+ private Long id;
+
+ /**
+ * 热度值
+ */
+ private Double heat;
+}
\ No newline at end of file
diff --git a/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/utils/HeatCalculator.java b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/utils/HeatCalculator.java
new file mode 100644
index 0000000..e8c384c
--- /dev/null
+++ b/han-note-comment/han-note-comment-biz/src/main/java/com/hanserwei/hannote/comment/biz/utils/HeatCalculator.java
@@ -0,0 +1,40 @@
+package com.hanserwei.hannote.comment.biz.utils;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+public class HeatCalculator {
+
+ // 热度计算的权重配置
+ private static final double LIKE_WEIGHT = 0.7; // 点赞权重 70%
+ private static final double REPLY_WEIGHT = 0.3; // 回复权重 30%
+
+ public static BigDecimal calculateHeat(long likeCount, long replyCount) {
+ // 点赞数权重 70%,被回复数权重 30%
+ BigDecimal likeWeight = new BigDecimal(LIKE_WEIGHT);
+ BigDecimal replyWeight = new BigDecimal(REPLY_WEIGHT);
+
+ // 转换点赞数和回复数为 BigDecimal
+ BigDecimal likeCountBD = new BigDecimal(likeCount);
+ BigDecimal replyCountBD = new BigDecimal(replyCount);
+
+ // 计算热度 (点赞数*点赞权重 + 回复数*回复权重)
+ BigDecimal heat = likeCountBD.multiply(likeWeight).add(replyCountBD.multiply(replyWeight));
+
+ // 四舍五入保留两位小数
+ return heat.setScale(2, RoundingMode.HALF_UP);
+ }
+
+ public static void main(String[] args) {
+ int likeCount = 150; // 点赞数
+ int replyCount = 10; // 被回复数
+
+ // 计算热度
+ BigDecimal heat = calculateHeat(likeCount, replyCount);
+
+ // 输出热度值
+ System.out.println("Calculated Heat: " + heat);
+ }
+
+
+}
\ No newline at end of file
diff --git a/han-note-comment/han-note-comment-biz/src/main/resources/mapperxml/CommentDOMapper.xml b/han-note-comment/han-note-comment-biz/src/main/resources/mapperxml/CommentDOMapper.xml
index 7751a6d..eb904bc 100644
--- a/han-note-comment/han-note-comment-biz/src/main/resources/mapperxml/CommentDOMapper.xml
+++ b/han-note-comment/han-note-comment-biz/src/main/resources/mapperxml/CommentDOMapper.xml
@@ -19,18 +19,35 @@
+
-
- 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
+
+ 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