diff --git a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/constant/RedisKeyConstants.java b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/constant/RedisKeyConstants.java index 6aacd22..c4eadb5 100644 --- a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/constant/RedisKeyConstants.java +++ b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/constant/RedisKeyConstants.java @@ -12,11 +12,21 @@ public class RedisKeyConstants { */ public static final String BLOOM_USER_NOTE_LIKE_LIST_KEY = "bloom:note:likes:"; + /** + * 布隆过滤器:用户笔记收藏 前缀 + */ + public static final String BLOOM_USER_NOTE_COLLECT_LIST_KEY = "bloom:note:collects:"; + /** * 用户笔记点赞列表 ZSet 前缀 */ public static final String USER_NOTE_LIKE_ZSET_KEY = "user:note:likes:"; + /** + * 用户笔记收藏列表 ZSet 前缀 + */ + public static final String USER_NOTE_COLLECT_ZSET_KEY = "user:note:collects:"; + /** * 构建完整的笔记详情 KEY @@ -37,6 +47,16 @@ public class RedisKeyConstants { return BLOOM_USER_NOTE_LIKE_LIST_KEY + userId; } + /** + * 构建完整的布隆过滤器:用户笔记收藏 KEY + * + * @param userId 用户ID + * @return 布隆过滤器:用户笔记收藏 KEY + */ + public static String buildBloomUserNoteCollectListKey(Long userId) { + return BLOOM_USER_NOTE_COLLECT_LIST_KEY + userId; + } + /** * 构建完整的用户笔记点赞列表 ZSet KEY * @@ -47,4 +67,13 @@ public class RedisKeyConstants { return USER_NOTE_LIKE_ZSET_KEY + userId; } + /** + * 构建完整的用户笔记收藏列表 ZSet KEY + * + * @param userId 用户ID + * @return 用户笔记收藏列表 ZSet KEY + */ + public static String buildUserNoteCollectZSetKey(Long userId) { + return USER_NOTE_COLLECT_ZSET_KEY + userId; + } } \ No newline at end of file diff --git a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/controller/NoteController.java b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/controller/NoteController.java index b553a5c..5b0fe80 100644 --- a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/controller/NoteController.java +++ b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/controller/NoteController.java @@ -68,4 +68,10 @@ public class NoteController { return noteService.unlikeNote(unlikeNoteReqVO); } + @PostMapping(value = "/collect") + @ApiOperationLog(description = "收藏笔记") + public Response collectNote(@Validated @RequestBody CollectNoteReqVO collectNoteReqVO) { + return noteService.collectNote(collectNoteReqVO); + } + } diff --git a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/domain/dataobject/NoteCollectionDO.java b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/domain/dataobject/NoteCollectionDO.java index e5eb5cf..83eea8f 100644 --- a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/domain/dataobject/NoteCollectionDO.java +++ b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/domain/dataobject/NoteCollectionDO.java @@ -4,12 +4,13 @@ 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 java.util.Date; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.time.LocalDateTime; + /** * 笔记收藏表 */ @@ -41,11 +42,11 @@ public class NoteCollectionDO { * 创建时间 */ @TableField(value = "create_time") - private Date createTime; + private LocalDateTime createTime; /** * 收藏状态(0:取消收藏 1:收藏) */ @TableField(value = "`status`") - private Byte status; + private Integer status; } \ No newline at end of file diff --git a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/enums/CollectStatusEnum.java b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/enums/CollectStatusEnum.java new file mode 100644 index 0000000..abf684d --- /dev/null +++ b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/enums/CollectStatusEnum.java @@ -0,0 +1,14 @@ +package com.hanserwei.hannote.note.biz.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum CollectStatusEnum { + COLLECT(1), // 收藏 + UNCOLLECTED(0), // 取消收藏 + ; + + private final Integer code; +} diff --git a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/enums/NoteCollectLuaResultEnum.java b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/enums/NoteCollectLuaResultEnum.java new file mode 100644 index 0000000..04328ea --- /dev/null +++ b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/enums/NoteCollectLuaResultEnum.java @@ -0,0 +1,35 @@ +package com.hanserwei.hannote.note.biz.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Objects; + +@Getter +@AllArgsConstructor +public enum NoteCollectLuaResultEnum { + // 布隆过滤器或者 ZSet 不存在 + NOT_EXIST(-1L), + // 笔记已收藏 + NOTE_COLLECTED(1L), + // 笔记收藏成功 + NOTE_COLLECTED_SUCCESS(0L), + ; + + private final Long code; + + /** + * 根据类型 code 获取对应的枚举 + * + * @param code 类型 code + * @return 枚举 + */ + public static NoteCollectLuaResultEnum valueOf(Long code) { + for (NoteCollectLuaResultEnum noteCollectLuaResultEnum : NoteCollectLuaResultEnum.values()) { + if (Objects.equals(code, noteCollectLuaResultEnum.getCode())) { + return noteCollectLuaResultEnum; + } + } + return null; + } +} \ No newline at end of file diff --git a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/enums/ResponseCodeEnum.java b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/enums/ResponseCodeEnum.java index 7913188..e8723f3 100644 --- a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/enums/ResponseCodeEnum.java +++ b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/enums/ResponseCodeEnum.java @@ -23,6 +23,7 @@ public enum ResponseCodeEnum implements BaseExceptionInterface { NOTE_CANT_OPERATE("NOTE-20007", "您无法操作该笔记"), NOTE_ALREADY_LIKED("NOTE-20008", "您已经点赞过该笔记"), NOTE_NOT_LIKED("NOTE-20009", "您未点赞该篇笔记,无法取消点赞"), + NOTE_ALREADY_COLLECTED("NOTE-20010", "您已经收藏过该笔记"), ; // 异常码 diff --git a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/model/vo/CollectNoteReqVO.java b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/model/vo/CollectNoteReqVO.java new file mode 100644 index 0000000..273ce80 --- /dev/null +++ b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/model/vo/CollectNoteReqVO.java @@ -0,0 +1,18 @@ +package com.hanserwei.hannote.note.biz.model.vo; + +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CollectNoteReqVO { + + @NotNull(message = "笔记 ID 不能为空") + private Long id; + +} \ No newline at end of file diff --git a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/service/NoteService.java b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/service/NoteService.java index caaa479..fee502c 100644 --- a/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/service/NoteService.java +++ b/han-note-note/han-note-note-biz/src/main/java/com/hanserwei/hannote/note/biz/service/NoteService.java @@ -65,4 +65,12 @@ public interface NoteService extends IService { */ Response unlikeNote(UnlikeNoteReqVO unlikeNoteReqVO); + /** + * 收藏笔记 + * + * @param collectNoteReqVO 收藏笔记请求 + * @return 收藏笔记结果 + */ + Response collectNote(CollectNoteReqVO collectNoteReqVO); + } \ No newline at end of file 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 76a40c3..40bab85 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 @@ -16,6 +16,7 @@ import com.hanserwei.framework.common.utils.DateUtils; import com.hanserwei.framework.common.utils.JsonUtils; import com.hanserwei.hannote.note.biz.constant.MQConstants; import com.hanserwei.hannote.note.biz.constant.RedisKeyConstants; +import com.hanserwei.hannote.note.biz.domain.dataobject.NoteCollectionDO; import com.hanserwei.hannote.note.biz.domain.dataobject.NoteDO; import com.hanserwei.hannote.note.biz.domain.dataobject.NoteLikeDO; import com.hanserwei.hannote.note.biz.domain.dataobject.TopicDO; @@ -26,6 +27,7 @@ import com.hanserwei.hannote.note.biz.model.vo.*; import com.hanserwei.hannote.note.biz.rpc.DistributedIdGeneratorRpcService; import com.hanserwei.hannote.note.biz.rpc.KeyValueRpcService; import com.hanserwei.hannote.note.biz.rpc.UserRpcService; +import com.hanserwei.hannote.note.biz.service.NoteCollectionDOService; import com.hanserwei.hannote.note.biz.service.NoteLikeDOService; import com.hanserwei.hannote.note.biz.service.NoteService; import com.hanserwei.hannote.note.biz.service.TopicDOService; @@ -37,6 +39,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.producer.SendCallback; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ClassPathResource; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; @@ -84,6 +87,8 @@ public class NoteServiceImpl extends ServiceImpl implement .build(); @Resource private NoteLikeDOService noteLikeDOService; + @Autowired + private NoteCollectionDOService noteCollectionDOService; @Override public Response publishNote(PublishNoteReqVO publishNoteReqVO) { @@ -794,6 +799,185 @@ public class NoteServiceImpl extends ServiceImpl implement return Response.success(); } + @Override + public Response collectNote(CollectNoteReqVO collectNoteReqVO) { + // 笔记ID + Long noteId = collectNoteReqVO.getId(); + + // 1. 校验被收藏的笔记是否存在 + checkNoteIsExist(noteId); + + // TODO: 2. 判断目标笔记,是否已经收藏过 + // 当前登录用户ID + Long userId = LoginUserContextHolder.getUserId(); + + // 布隆过滤器Key + String bloomUserNoteCollectListKey = RedisKeyConstants.buildBloomUserNoteCollectListKey(userId); + // 构建 Redis Key + String userNoteCollectZSetKey = RedisKeyConstants.buildUserNoteCollectZSetKey(userId); + + DefaultRedisScript script = new DefaultRedisScript<>(); + // Lua 脚本路径 + script.setScriptSource(new ResourceScriptSource(new ClassPathResource("/lua/bloom_note_collect_check.lua"))); + // 返回值类型 + script.setResultType(Long.class); + + // 执行 Lua 脚本,拿到返回结果 + Long result = redisTemplate.execute(script, Collections.singletonList(bloomUserNoteCollectListKey), noteId); + + NoteCollectLuaResultEnum noteCollectLuaResultEnum = NoteCollectLuaResultEnum.valueOf(result); + log.info("==> 【笔记收藏】Lua 脚本返回结果: {}", noteCollectLuaResultEnum); + assert noteCollectLuaResultEnum != null; + switch (noteCollectLuaResultEnum) { + // 布隆过滤器不存在 + case NOT_EXIST -> { + // 从数据库中校验笔记是否被收藏,并异步初始化布隆过滤器,设置过期时间 + long count = noteCollectionDOService.count(new LambdaQueryWrapper<>(NoteCollectionDO.class) + .eq(NoteCollectionDO::getUserId, userId) + .eq(NoteCollectionDO::getNoteId, noteId) + .eq(NoteCollectionDO::getStatus, CollectStatusEnum.COLLECT.getCode())); + // 设置隋朝过期时间 + long expireSeconds = 60 * 60 * 24 + RandomUtil.randomInt(60 * 60 * 24); + + // 若目标笔记已经收藏 + if (count > 0) { + // 异步初始化布隆过滤器 + threadPoolTaskExecutor.submit(() -> { + batchAddNoteCollect2BloomAndExpire(userId, expireSeconds, bloomUserNoteCollectListKey); + }); + throw new ApiException(ResponseCodeEnum.NOTE_ALREADY_COLLECTED); + } + // 若目标笔记未被收藏,查询当前用户是否有收藏其他笔记,有则同步初始化布隆过滤器 + batchAddNoteCollect2BloomAndExpire(userId, expireSeconds, bloomUserNoteCollectListKey); + // 添加当前收藏笔记 ID 到布隆过滤器中 + script.setScriptSource(new ResourceScriptSource(new ClassPathResource("/lua/bloom_add_note_collect_and_expire.lua"))); + // 返回值类型 + script.setResultType(Long.class); + redisTemplate.execute(script, Collections.singletonList(bloomUserNoteCollectListKey), noteId, expireSeconds); + } + // 目标笔记已经被收藏 (可能存在误判,需要进一步确认) + case NOTE_COLLECTED -> { + // 校验ZSet列表中是否有被收藏的笔记ID + Double score = redisTemplate.opsForZSet().score(userNoteCollectZSetKey, noteId); + if (Objects.nonNull(score)) { + throw new ApiException(ResponseCodeEnum.NOTE_ALREADY_COLLECTED); + } + // 若score为空,则说明该笔记未被收藏,查数据库确认 + long count = noteCollectionDOService.count(new LambdaQueryWrapper<>(NoteCollectionDO.class) + .eq(NoteCollectionDO::getUserId, userId) + .eq(NoteCollectionDO::getNoteId, noteId) + .eq(NoteCollectionDO::getStatus, CollectStatusEnum.COLLECT.getCode())); + if (count > 0) { + // 数据库里面有收藏记录,而 Redis 中 ZSet 已过期被删除的话,需要重新异步初始化 ZSet + asynInitUserNoteCollectsZSet(userId, userNoteCollectZSetKey); + throw new ApiException(ResponseCodeEnum.NOTE_ALREADY_COLLECTED); + } + } + } + + // TODO: 3. 更新用户 ZSET 收藏列表 + + // TODO: 4. 发送 MQ, 将收藏数据落库 + + return Response.success(); + } + + /** + * 异步初始化用户收藏笔记 ZSet + * + * @param userId 用户ID + * @param userNoteCollectZSetKey 用户收藏笔记 ZSet KEY + */ + private void asynInitUserNoteCollectsZSet(Long userId, String userNoteCollectZSetKey) { + threadPoolTaskExecutor.submit(() -> { + // 判断用户笔记收藏 ZSET 是否存在 + boolean hasKey = redisTemplate.hasKey(userNoteCollectZSetKey); + + // 不存在则初始化 + if (!hasKey) { + // 查询当前用户最新收藏的 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(); + if (CollUtil.isNotEmpty(noteCollectionDOS)) { + // 保底1天+随机秒数 + long expireSeconds = 60 * 60 * 24 + RandomUtil.randomInt(60 * 60 * 24); + // 构建 Lua 参数 + Object[] luaArgs = buildNoteCollectZSetLuaArgs(noteCollectionDOS, expireSeconds); + + DefaultRedisScript script2 = new DefaultRedisScript<>(); + // Lua 脚本路径 + script2.setScriptSource(new ResourceScriptSource(new ClassPathResource("/lua/batch_add_note_collect_zset_and_expire.lua"))); + // 返回值类型 + script2.setResultType(Long.class); + + redisTemplate.execute(script2, Collections.singletonList(userNoteCollectZSetKey), luaArgs); + } + } + }); + } + + /** + * 构建笔记收藏 ZSET Lua 脚本参数 + * + * @param noteCollectionDOS 笔记收藏列表 + * @param expireSeconds 过期时间 + * @return Lua 脚本参数 + */ + private Object[] buildNoteCollectZSetLuaArgs(List noteCollectionDOS, long expireSeconds) { + int argsLength = noteCollectionDOS.size() * 2 + 1; // 每个笔记收藏关系有 2 个参数(score 和 value),最后再跟一个过期时间 + Object[] luaArgs = new Object[argsLength]; + + int i = 0; + for (NoteCollectionDO noteCollectionDO : noteCollectionDOS) { + // 收藏时间作为 score + luaArgs[i] = DateUtils.localDateTime2Timestamp(noteCollectionDO.getCreateTime()); + // 笔记ID 作为 ZSet value + luaArgs[i + 1] = noteCollectionDO.getNoteId(); + i += 2; + } + + luaArgs[argsLength - 1] = expireSeconds; // 最后一个参数是 ZSet 的过期时间 + return luaArgs; + } + + /** + * 批量添加用户收藏笔记到布隆过滤器中 + * + * @param userId 用户ID + * @param expireSeconds 过期时间 + * @param bloomUserNoteCollectListKey 布隆过滤器:用户收藏笔记 + */ + private void batchAddNoteCollect2BloomAndExpire(Long userId, long expireSeconds, String bloomUserNoteCollectListKey) { + try { + // 异步全量同步一下,并设置过期时间 + List noteCollectionDOS = noteLikeDOService.list(new LambdaQueryWrapper<>(NoteLikeDO.class) + .select(NoteLikeDO::getNoteId) + .eq(NoteLikeDO::getUserId, userId) + .eq(NoteLikeDO::getStatus, CollectStatusEnum.COLLECT.getCode())); + if (CollUtil.isNotEmpty(noteCollectionDOS)) { + DefaultRedisScript script = new DefaultRedisScript<>(); + // Lua 脚本路径 + script.setScriptSource(new ResourceScriptSource(new ClassPathResource("/lua/bloom_batch_add_note_collect_and_expire.lua"))); + // 返回值类型 + script.setResultType(Long.class); + + // 构造Lua参数 + List luaParams = Lists.newArrayList(); + // 将每个收藏的笔记 ID 传入 + noteCollectionDOS.forEach(noteLikeDO -> luaParams.add(noteLikeDO.getNoteId())); + // 最后一个参数是过期时间 + luaParams.add(expireSeconds); + redisTemplate.execute(script, Collections.singletonList(bloomUserNoteCollectListKey), luaParams.toArray()); + } + } catch (Exception e) { + log.error("## 异步初始化【笔记收藏】布隆过滤器异常: ", e); + } + } + /** * 异步初始化用户点赞笔记 ZSet * diff --git a/han-note-note/han-note-note-biz/src/main/resources/lua/batch_add_note_collect_zset_and_expire.lua b/han-note-note/han-note-note-biz/src/main/resources/lua/batch_add_note_collect_zset_and_expire.lua new file mode 100644 index 0000000..6d6e2c7 --- /dev/null +++ b/han-note-note/han-note-note-biz/src/main/resources/lua/batch_add_note_collect_zset_and_expire.lua @@ -0,0 +1,20 @@ +-- 操作的 Key +local key = KEYS[1] + +-- 准备批量添加数据的参数表 +local zaddArgs = {} + +-- 遍历 ARGV 参数,将分数和值按顺序插入到 zaddArgs 变量中 +for i = 1, #ARGV - 1, 2 do + table.insert(zaddArgs, ARGV[i]) -- 分数(收藏时间) + table.insert(zaddArgs, ARGV[i + 1]) -- 值(笔记ID) +end + +-- 调用 ZADD 批量插入数据 +redis.call('ZADD', key, unpack(zaddArgs)) + +-- 设置 ZSet 的过期时间 +local expireTime = ARGV[#ARGV] -- 最后一个参数为过期时间 +redis.call('EXPIRE', key, expireTime) + +return 0 diff --git a/han-note-note/han-note-note-biz/src/main/resources/lua/bloom_add_note_collect_and_expire.lua b/han-note-note/han-note-note-biz/src/main/resources/lua/bloom_add_note_collect_and_expire.lua new file mode 100644 index 0000000..5d88daf --- /dev/null +++ b/han-note-note/han-note-note-biz/src/main/resources/lua/bloom_add_note_collect_and_expire.lua @@ -0,0 +1,10 @@ +-- 操作的 Key +local key = KEYS[1] +local noteId = ARGV[1] -- 笔记ID +local expireSeconds = ARGV[2] -- 过期时间(秒) + +redis.call("BF.ADD", key, noteId) + +-- 设置过期时间 +redis.call("EXPIRE", key, expireSeconds) +return 0 \ No newline at end of file diff --git a/han-note-note/han-note-note-biz/src/main/resources/lua/bloom_batch_add_note_collect_and_expire.lua b/han-note-note/han-note-note-biz/src/main/resources/lua/bloom_batch_add_note_collect_and_expire.lua new file mode 100644 index 0000000..4d2345b --- /dev/null +++ b/han-note-note/han-note-note-biz/src/main/resources/lua/bloom_batch_add_note_collect_and_expire.lua @@ -0,0 +1,12 @@ +-- 操作的 Key +local key = KEYS[1] + +for i = 1, #ARGV - 1 do + redis.call("BF.ADD", key, ARGV[i]) +end + +---- 最后一个参数为过期时间 +local expireTime = ARGV[#ARGV] +-- 设置过期时间 +redis.call("EXPIRE", key, expireTime) +return 0 diff --git a/han-note-note/han-note-note-biz/src/main/resources/lua/bloom_note_collect_check.lua b/han-note-note/han-note-note-biz/src/main/resources/lua/bloom_note_collect_check.lua new file mode 100644 index 0000000..ede6816 --- /dev/null +++ b/han-note-note/han-note-note-biz/src/main/resources/lua/bloom_note_collect_check.lua @@ -0,0 +1,20 @@ +-- LUA 脚本:笔记收藏布隆过滤器 + +local key = KEYS[1] -- 操作的 Redis Key +local noteId = ARGV[1] -- 笔记ID + +-- 使用 EXISTS 命令检查布隆过滤器是否存在 +local exists = redis.call('EXISTS', key) +if exists == 0 then + return -1 +end + +-- 校验该篇笔记是否被收藏过(1 表示已经收藏,0 表示未收藏) +local isCollected = redis.call('BF.EXISTS', key, noteId) +if isCollected == 1 then + return 1 +end + +-- 未被收藏,添加收藏数据 +redis.call('BF.ADD', key, noteId) +return 0 \ No newline at end of file diff --git a/http-client/gateApi.http b/http-client/gateApi.http index 13a1aed..16a07cc 100644 --- a/http-client/gateApi.http +++ b/http-client/gateApi.http @@ -199,6 +199,15 @@ POST http://localhost:8000/note/note/unlike Content-Type: application/json Authorization: Bearer {{token}} +{ + "id": 1977249693272375330 +} + +### 笔记收藏入口 +POST http://localhost:8000/note/note/collect +Content-Type: application/json +Authorization: Bearer {{token}} + { "id": 1977249693272375330 } \ No newline at end of file