feat(count): 实现笔记发布与删除的计数更新功能

- 新增笔记操作 MQ 消费者 CountNotePublishConsumer
- 支持处理笔记发布和删除消息,更新 Redis 和数据库计数
- 新增笔记操作相关常量:TOPIC_NOTE_OPERATE、TAG_NOTE_PUBLISH、TAG_NOTE_DELETE
- 定义笔记操作 DTO:NoteOperateMqDTO,用于 MQ 消息传递
- 在笔记服务中发送笔记发布和删除的 MQ 消息
- 新增 Redis Hash 字段 noteTotal 用于存储笔记总数
- 新增数据库操作 insertOrUpdateNoteTotalByUserId 用于更新笔记总数
This commit is contained in:
2025-10-19 17:58:57 +08:00
parent 7b1df60c05
commit 7fc24e1e2a
11 changed files with 272 additions and 4 deletions

View File

@@ -42,4 +42,19 @@ public interface MQConstants {
*/
String TOPIC_COUNT_NOTE_COLLECT_2_DB = "CountNoteCollect2DBTTopic";
/**
* Topic: 笔记操作(发布、删除)
*/
String TOPIC_NOTE_OPERATE = "NoteOperateTopic";
/**
* Tag 标签:笔记发布
*/
String TAG_NOTE_PUBLISH = "publishNote";
/**
* Tag 标签:笔记删除
*/
String TAG_NOTE_DELETE = "deleteNote";
}

View File

@@ -12,6 +12,11 @@ public class RedisKeyConstants {
*/
public static final String FIELD_FOLLOWING_TOTAL = "followingTotal";
/**
* Hash Field: 笔记发布总数
*/
public static final String FIELD_NOTE_TOTAL = "noteTotal";
/**
* 用户维度计数 Key 前缀
*/

View File

@@ -0,0 +1,79 @@
package com.hanserwei.hannote.count.biz.consumer;
import com.hanserwei.framework.common.utils.JsonUtils;
import com.hanserwei.hannote.count.biz.constant.MQConstants;
import com.hanserwei.hannote.count.biz.constant.RedisKeyConstants;
import com.hanserwei.hannote.count.biz.domain.mapper.UserCountDOMapper;
import com.hanserwei.hannote.count.biz.model.dto.NoteOperateMqDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Objects;
@Component
@Slf4j
@RocketMQMessageListener(
consumerGroup = "han_note_group_" + MQConstants.TOPIC_NOTE_OPERATE,
topic = MQConstants.TOPIC_NOTE_OPERATE
)
public class CountNotePublishConsumer implements RocketMQListener<Message> {
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private UserCountDOMapper userCountDOMapper;
@Override
public void onMessage(Message message) {
// 消息体
String bodyJsonStr = new String(message.getBody());
// 标签
String tags = message.getTags();
log.info("==> CountNotePublishConsumer 消费了消息 {}, tags: {}", bodyJsonStr, tags);
// 根据 MQ 标签,判断笔记操作类型
if (Objects.equals(tags, MQConstants.TAG_NOTE_PUBLISH)) { // 笔记发布
handleTagMessage(bodyJsonStr, 1);
} else if (Objects.equals(tags, MQConstants.TAG_NOTE_DELETE)) { // 笔记删除
handleTagMessage(bodyJsonStr, -1);
}
}
/**
* 处理笔记发布和笔记删除的 MQ 消息
*
* @param bodyJsonStr 笔记发布或删除的 MQ 消息体
* @param count 笔记发布或删除的计数
*/
private void handleTagMessage(String bodyJsonStr, long count) {
// 消息体 JSON 字符串转 DTO
NoteOperateMqDTO noteOperateMqDTO = JsonUtils.parseObject(bodyJsonStr, NoteOperateMqDTO.class);
if (Objects.isNull(noteOperateMqDTO)) return;
// 笔记发布者 ID
Long creatorId = noteOperateMqDTO.getCreatorId();
// 更新 Redis 中用户维度的计数 Hash
String countUserRedisKey = RedisKeyConstants.buildCountUserKey(creatorId);
// 判断 Redis 中 Hash 是否存在
boolean isCountUserExisted = redisTemplate.hasKey(countUserRedisKey);
// 若存在才会更新
// (因为缓存设有过期时间,考虑到过期后,缓存会被删除,这里需要判断一下,存在才会去更新,而初始化工作放在查询计数来做)
if (isCountUserExisted) {
// 对目标用户 Hash 中的笔记发布总数,进行加减操作
redisTemplate.opsForHash().increment(countUserRedisKey, RedisKeyConstants.FIELD_NOTE_TOTAL, count);
}
// 更新 t_user_count 表
userCountDOMapper.insertOrUpdateNoteTotalByUserId(count, creatorId);
}
}

View File

@@ -43,4 +43,13 @@ public interface UserCountDOMapper extends BaseMapper<UserCountDO> {
* @return 影响行数
*/
int insertOrUpdateCollectTotalByUserId(@Param("count") Integer count, @Param("userId") Long userId);
/**
* 添加记录或更新笔记发布数
*
* @param count 笔记发布数
* @param userId 用户ID
* @return 影响行数
*/
int insertOrUpdateNoteTotalByUserId(@Param("count") Long count, @Param("userId") Long userId);
}

View File

@@ -0,0 +1,29 @@
package com.hanserwei.hannote.count.biz.model.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class NoteOperateMqDTO {
/**
* 笔记发布者 ID
*/
private Long creatorId;
/**
* 笔记 ID
*/
private Long noteId;
/**
* 操作类型: 0 - 笔记删除; 1笔记发布
*/
private Integer type;
}

View File

@@ -40,4 +40,10 @@
VALUES (#{userId}, #{count})
ON DUPLICATE KEY UPDATE collect_total = collect_total + (#{count});
</insert>
<insert id="insertOrUpdateNoteTotalByUserId" parameterType="map">
INSERT INTO t_user_count (user_id, note_total)
VALUES (#{userId}, #{count})
ON DUPLICATE KEY UPDATE note_total = note_total + (#{count});
</insert>
</mapper>