diff --git a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/service/impl/NoteServiceImpl.java b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/service/impl/NoteServiceImpl.java index 40bab85..c5ae350 100644 --- a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/service/impl/NoteServiceImpl.java +++ b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/service/impl/NoteServiceImpl.java @@ -807,7 +807,7 @@ public class NoteServiceImpl extends ServiceImpl implement // 1. 校验被收藏的笔记是否存在 checkNoteIsExist(noteId); - // TODO: 2. 判断目标笔记,是否已经收藏过 + // 2. 判断目标笔记,是否已经收藏过 // 当前登录用户ID Long userId = LoginUserContextHolder.getUserId(); @@ -875,7 +875,54 @@ public class NoteServiceImpl extends ServiceImpl implement } } - // TODO: 3. 更新用户 ZSET 收藏列表 + // 3. 更新用户 ZSET 收藏列表 + // 3. 更新用户 ZSET 收藏列表 + LocalDateTime now = LocalDateTime.now(); + // Lua 脚本路径 + script.setScriptSource(new ResourceScriptSource(new ClassPathResource("/lua/note_collect_check_and_update_zset.lua"))); + // 返回值类型 + script.setResultType(Long.class); + + // 执行 Lua 脚本,拿到返回结果 + result = redisTemplate.execute(script, Collections.singletonList(userNoteCollectZSetKey), noteId, DateUtils.localDateTime2Timestamp(now)); + + // 若 ZSet 列表不存在,需要重新初始化 + if (Objects.equals(result, NoteCollectLuaResultEnum.NOT_EXIST.getCode())) { + // 查询当前用户最新收藏的 300 篇笔记 + Page page = noteCollectionDOService.page(new Page<>(1, 300), new LambdaQueryWrapper<>(NoteCollectionDO.class) + .select(NoteCollectionDO::getNoteId, NoteCollectionDO::getCreateTime) + .eq(NoteCollectionDO::getUserId, userId) + .eq(NoteCollectionDO::getStatus, CollectStatusEnum.COLLECT.getCode()) + .orderByDesc(NoteCollectionDO::getCreateTime)); + List noteCollectionDOS = page.getRecords(); + // 保底1天+随机秒数 + long expireSeconds = 60 * 60 * 24 + RandomUtil.randomInt(60 * 60 * 24); + + DefaultRedisScript script2 = new DefaultRedisScript<>(); + // Lua 脚本路径 + script2.setScriptSource(new ResourceScriptSource(new ClassPathResource("/lua/batch_add_note_collect_zset_and_expire.lua"))); + // 返回值类型 + script2.setResultType(Long.class); + + // 若数据库中存在历史收藏笔记,需要批量同步 + if (CollUtil.isNotEmpty(noteCollectionDOS)) { + // 构建 Lua 参数 + Object[] luaArgs = buildNoteCollectZSetLuaArgs(noteCollectionDOS, expireSeconds); + + redisTemplate.execute(script2, Collections.singletonList(userNoteCollectZSetKey), luaArgs); + + // 再次调用 note_collect_check_and_update_zset.lua 脚本,将当前收藏的笔记添加到 zset 中 + redisTemplate.execute(script, Collections.singletonList(userNoteCollectZSetKey), noteId, DateUtils.localDateTime2Timestamp(now)); + } else { // 若无历史收藏的笔记,则直接将当前收藏的笔记 ID 添加到 ZSet 中,随机过期时间 + List luaArgs = Lists.newArrayList(); + luaArgs.add(DateUtils.localDateTime2Timestamp(LocalDateTime.now())); // score:收藏时间戳 + luaArgs.add(noteId); // 当前收藏的笔记 ID + luaArgs.add(expireSeconds); // 随机过期时间 + + redisTemplate.execute(script2, Collections.singletonList(userNoteCollectZSetKey), luaArgs.toArray()); + } + } + // TODO: 4. 发送 MQ, 将收藏数据落库 diff --git a/han-note-note/han-note-note-biz/src/main/resources/lua/note_collect_check_and_update_zset.lua b/han-note-note/han-note-note-biz/src/main/resources/lua/note_collect_check_and_update_zset.lua new file mode 100644 index 0000000..2f14e43 --- /dev/null +++ b/han-note-note/han-note-note-biz/src/main/resources/lua/note_collect_check_and_update_zset.lua @@ -0,0 +1,21 @@ +local key = KEYS[1] -- Redis Key +local noteId = ARGV[1] -- 笔记ID +local timestamp = ARGV[2] -- 时间戳 + +-- 使用 EXISTS 命令检查 ZSET 笔记收藏列表是否存在 +local exists = redis.call('EXISTS', key) +if exists == 0 then + return -1 +end + +-- 获取笔记收藏列表大小 +local size = redis.call('ZCARD', key) + +-- 若已经收藏了 300 篇笔记,则移除最早收藏的那篇 +if size >= 300 then + redis.call('ZPOPMIN', key) +end + +-- 添加新的笔记收藏关系 +redis.call('ZADD', key, timestamp, noteId) +return 0