feat(count): 新增笔记收藏与点赞计数聚合功能,用户维度统计功能

- 新增 AggregationCountCollectedUncollectedNoteMqDTO 和 AggregationCountLikeUnlikeNoteMqDTO 聚合消息体
- 在 CollectUnCollectNoteMqDTO、CountCollectUnCollectNoteMqDTO 和 CountLikeUnlikeNoteMqDTO 中添加 noteCreatorId 字段
- 优化 CountNoteCollect2DBConsumer 和 CountNoteLike2DBConsumer 消费者逻辑,支持事务性更新用户及笔记计数
- 修改 CountNoteCollectConsumer 和 CountNoteLikeConsumer,使用聚合 DTO 替代 Map 结构处理计数逻辑
- 扩展 JsonUtils 工具类,新增 parseList 方法用于解析 JSON 到 List 对象
- 更新 NoteServiceImpl 中点赞和收藏相关方法,补充获取并传递 noteCreatorId 参数
- 在 UserCountDOMapper 及其 XML 映射文件中新增点赞数和收藏数的插入或更新操作接口
This commit is contained in:
2025-10-19 17:18:20 +08:00
parent 564eefa7bc
commit 7b1df60c05
14 changed files with 295 additions and 54 deletions

View File

@@ -23,4 +23,9 @@ public class CollectUnCollectNoteMqDTO {
private Integer type;
private LocalDateTime createTime;
/**
* 笔记发布者 ID
*/
private Long noteCreatorId;
}

View File

@@ -23,4 +23,9 @@ public class LikeUnlikeNoteMqDTO {
private Integer type;
private LocalDateTime createTime;
/**
* 笔记发布者 ID
*/
private Long noteCreatorId;
}

View File

@@ -571,7 +571,7 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
public Response<?> likeNote(LikeNoteReqVO likeNoteReqVO) {
Long noteId = likeNoteReqVO.getId();
// 1. 校验被点赞的笔记是否存在
checkNoteIsExist(noteId);
Long creatorId = checkNoteIsExistAndGetCreatorId(noteId);
// 2. 判断目标笔记,是否已经点赞过
Long userId = LoginUserContextHolder.getUserId();
@@ -593,7 +593,7 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
switch (noteLikeLuaResultEnum) {
// Redis 中布隆过滤器不存在
case NOT_EXIST -> {
// TODO: 从数据库中校验笔记是否被点赞,并异步初始化布隆过滤器,设置过期时间
//从数据库中校验笔记是否被点赞,并异步初始化布隆过滤器,设置过期时间
long count = noteLikeDOService.count(new LambdaQueryWrapper<>(NoteLikeDO.class)
.eq(NoteLikeDO::getNoteId, noteId)
.eq(NoteLikeDO::getStatus, LikeStatusEnum.LIKE.getCode()));
@@ -689,6 +689,7 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
.noteId(noteId)
.type(LikeStatusEnum.LIKE.getCode()) // 点赞
.createTime(now)
.noteCreatorId(creatorId)
.build();
// 构建消息将DTO转换为JSON字符串设置到消息体中
Message<String> message = MessageBuilder.withPayload(JsonUtils.toJsonString(likeUnlikeNoteMqDTO)).build();
@@ -717,7 +718,7 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
Long noteId = unlikeNoteReqVO.getId();
// 1. 校验笔记是否真实存在
checkNoteIsExist(noteId);
Long creatorId = checkNoteIsExistAndGetCreatorId(noteId);
// 2. 校验笔记是否被点赞过
// 当前登录用户ID
@@ -774,6 +775,7 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
.noteId(noteId)
.type(LikeUnlikeNoteTypeEnum.UNLIKE.getCode()) // 取消点赞笔记
.createTime(LocalDateTime.now())
.noteCreatorId(creatorId)
.build();
// 构建消息将DTO转换为JSON字符串设置到消息体中
@@ -806,7 +808,7 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
Long noteId = collectNoteReqVO.getId();
// 1. 校验被收藏的笔记是否存在
checkNoteIsExist(noteId);
Long creatorId = checkNoteIsExistAndGetCreatorId(noteId);
// 2. 判断目标笔记,是否已经收藏过
// 当前登录用户ID
@@ -828,8 +830,7 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
NoteCollectLuaResultEnum noteCollectLuaResultEnum = NoteCollectLuaResultEnum.valueOf(result);
log.info("==> 【笔记收藏】Lua 脚本返回结果: {}", noteCollectLuaResultEnum);
assert noteCollectLuaResultEnum != null;
switch (noteCollectLuaResultEnum) {
switch (Objects.requireNonNull(noteCollectLuaResultEnum)) {
// 布隆过滤器不存在
case NOT_EXIST -> {
// 从数据库中校验笔记是否被收藏,并异步初始化布隆过滤器,设置过期时间
@@ -932,6 +933,7 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
.noteId(noteId)
.type(CollectUnCollectNoteTypeEnum.COLLECT.getCode()) // 收藏笔记
.createTime(now)
.noteCreatorId(creatorId)
.build();
// 构建消息对象,并将 DTO 转成 Json 字符串设置到消息体中
@@ -965,7 +967,7 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
Long noteId = unCollectNoteReqVO.getId();
// 1. 校验笔记是否真实存在
checkNoteIsExist(noteId);
Long creatorId = checkNoteIsExistAndGetCreatorId(noteId);
// 2. 校验笔记是否被收藏过
// 当前登录用户ID
@@ -1021,6 +1023,7 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
.noteId(noteId)
.type(CollectUnCollectNoteTypeEnum.UN_COLLECT.getCode()) // 取消收藏笔记
.createTime(LocalDateTime.now())
.noteCreatorId(creatorId)
.build();
// 构建消息对象,并将 DTO 转成 Json 字符串设置到消息体中
@@ -1238,17 +1241,17 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
}
/**
* 校验笔记是否存在
* 校验笔记是否存在,若存在,则获取笔记的发布者 ID
*
* @param noteId 笔记 ID
*/
private void checkNoteIsExist(Long noteId) {
private Long checkNoteIsExistAndGetCreatorId(Long noteId) {
// 先从本地缓存中检验
String findNoteDetailRspVOStrLocalCache = LOCAL_CACHE.getIfPresent(noteId);
// 解析 JSON 为 FindNoteDetailRspVO
FindNoteDetailRspVO findNoteDetailRspVO = JsonUtils.parseObject(findNoteDetailRspVOStrLocalCache, FindNoteDetailRspVO.class);
// 若缓存不存在
// 若本地缓存不存在
if (Objects.isNull(findNoteDetailRspVO)) {
// 从 Redis 中获取
String noteDetailRedisKey = RedisKeyConstants.buildNoteDetailKey(noteId);
@@ -1260,10 +1263,15 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
// 若 Redis 中不存在,则从数据库中获取
if (Objects.isNull(findNoteDetailRspVO)) {
boolean isExist = this.exists(new LambdaQueryWrapper<>(NoteDO.class)
// 查询笔记的发布者用户 ID
NoteDO noteDO = this.getOne(new LambdaQueryWrapper<>(NoteDO.class)
.select(NoteDO::getCreatorId)
.eq(NoteDO::getId, noteId)
.eq(NoteDO::getStatus, NoteStatusEnum.NORMAL.getCode()));
if (!isExist) {
// 笔记发布者用户 ID
Long creatorId = noteDO.getCreatorId();
// 若数据库中也不存在,提示用户
if (Objects.isNull(creatorId)) {
throw new ApiException(ResponseCodeEnum.NOTE_NOT_FOUND);
}
// 缓存
@@ -1271,8 +1279,11 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
FindNoteDetailReqVO findNoteDetailReqVO = FindNoteDetailReqVO.builder().id(noteId).build();
findNoteDetail(findNoteDetailReqVO);
});
return creatorId;
}
}
return findNoteDetailRspVO.getCreatorId();
}
/**