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 dd8eaf9..8e5a0a0 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 @@ -39,6 +39,7 @@ import java.time.LocalDateTime; import java.util.List; import java.util.Objects; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @Slf4j @@ -167,6 +168,7 @@ public class NoteServiceImpl extends ServiceImpl implement } @Override + @SneakyThrows public Response findNoteDetail(FindNoteDetailReqVO findNoteDetailReqVO) { // 查询笔记ID Long noteId = findNoteDetailReqVO.getId(); @@ -208,7 +210,7 @@ public class NoteServiceImpl extends ServiceImpl implement .eq(NoteDO::getStatus, 1)); // 若笔记不存在,则抛异常 - if (Objects.isNull(noteDO)){ + if (Objects.isNull(noteDO)) { threadPoolTaskExecutor.execute(() -> { // 防止缓存穿透,将空数据存入 Redis 缓存 (过期时间不宜设置过长) // 保底1分钟 + 随机秒数 @@ -224,47 +226,61 @@ public class NoteServiceImpl extends ServiceImpl implement // RPC调用用户服务,获取用户信息 Long creatorId = noteDO.getCreatorId(); - FindUserByIdRspDTO findUserByIdRspDTO = userRpcService.findById(creatorId); + CompletableFuture userResultFuture = CompletableFuture + .supplyAsync(() -> userRpcService.findById(creatorId), threadPoolTaskExecutor); // RPC: 调用 K-V 存储服务获取内容 - String content = null; + CompletableFuture contentResultFuture = CompletableFuture.completedFuture(null); if (Objects.equals(noteDO.getIsContentEmpty(), Boolean.FALSE)) { - content = keyValueRpcService.findNoteContent(noteDO.getContentUuid()); + contentResultFuture = CompletableFuture + .supplyAsync(() -> keyValueRpcService.findNoteContent(noteDO.getContentUuid()), threadPoolTaskExecutor); } + CompletableFuture finalContentResultFuture = contentResultFuture; + CompletableFuture resultFuture = CompletableFuture + .allOf(userResultFuture, contentResultFuture) + .thenApply(s -> { + // 获取 Future 返回的结果 + FindUserByIdRspDTO findUserByIdRspDTO = userResultFuture.join(); + String content = finalContentResultFuture.join(); - // 笔记类型 - Integer noteType = noteDO.getType(); - // 图文笔记图片链接(字符串) - String imgUrisStr = noteDO.getImgUris(); - // 图文笔记图片链接(集合) - List imgUris = null; - // 如果查询的是图文笔记,需要将图片链接的逗号分隔开,转换成集合 - if (Objects.equals(noteType, NoteTypeEnum.IMAGE_TEXT.getCode()) - && StringUtils.isNotBlank(imgUrisStr)) { - imgUris = List.of(imgUrisStr.split(",")); - } + // 笔记类型 + Integer noteType = noteDO.getType(); + // 图文笔记图片链接(字符串) + String imgUrisStr = noteDO.getImgUris(); + // 图文笔记图片链接(集合) + List imgUris = null; + // 如果查询的是图文笔记,需要将图片链接的逗号分隔开,转换成集合 + if (Objects.equals(noteType, NoteTypeEnum.IMAGE_TEXT.getCode()) + && StringUtils.isNotBlank(imgUrisStr)) { + imgUris = List.of(imgUrisStr.split(",")); + } - // 构建返参 VO 实体类 - FindNoteDetailRspVO findNoteDetailRspVO = FindNoteDetailRspVO.builder() - .id(noteDO.getId()) - .type(noteDO.getType()) - .title(noteDO.getTitle()) - .content(content) - .imgUris(imgUris) - .topicId(noteDO.getTopicId()) - .topicName(noteDO.getTopicName()) - .creatorId(noteDO.getCreatorId()) - .creatorName(findUserByIdRspDTO.getNickName()) - .avatar(findUserByIdRspDTO.getAvatar()) - .videoUri(noteDO.getVideoUri()) - .updateTime(noteDO.getUpdateTime()) - .visible(noteDO.getVisible()) - .build(); + // 构建返参 VO 实体类 + return FindNoteDetailRspVO.builder() + .id(noteDO.getId()) + .type(noteDO.getType()) + .title(noteDO.getTitle()) + .content(content) + .imgUris(imgUris) + .topicId(noteDO.getTopicId()) + .topicName(noteDO.getTopicName()) + .creatorId(noteDO.getCreatorId()) + .creatorName(findUserByIdRspDTO.getNickName()) + .avatar(findUserByIdRspDTO.getAvatar()) + .videoUri(noteDO.getVideoUri()) + .updateTime(noteDO.getUpdateTime()) + .visible(noteDO.getVisible()) + .build(); + + }); + + // 获取拼装后的 FindNoteDetailRspVO + FindNoteDetailRspVO findNoteDetailRspVO = resultFuture.get(); // 异步线程中将笔记详情存入 Redis threadPoolTaskExecutor.submit(() -> { String noteDetailJson1 = JsonUtils.toJsonString(findNoteDetailRspVO); // 过期时间(保底1天 + 随机秒数,将缓存过期时间打散,防止同一时间大量缓存失效,导致数据库压力太大) - long expireSeconds = 60*60*24 + RandomUtil.randomInt(60*60*24); + long expireSeconds = 60 * 60 * 24 + RandomUtil.randomInt(60 * 60 * 24); redisTemplate.opsForValue().set(noteDetailRedisKey, noteDetailJson1, expireSeconds, TimeUnit.SECONDS); }); return Response.success(findNoteDetailRspVO); @@ -272,8 +288,9 @@ public class NoteServiceImpl extends ServiceImpl implement /** * 校验笔记的可见性 - * @param visible 是否可见 - * @param userId 当前用户 ID + * + * @param visible 是否可见 + * @param userId 当前用户 ID * @param creatorId 笔记创建者 */ private void checkNoteVisible(Integer visible, Long userId, Long creatorId) { @@ -285,7 +302,8 @@ public class NoteServiceImpl extends ServiceImpl implement /** * 校验笔记的可见性(针对 VO 实体类) - * @param userId 当前用户 ID + * + * @param userId 当前用户 ID * @param findNoteDetailRspVO 笔记详情VO类 */ private void checkNoteVisibleFromVO(Long userId, FindNoteDetailRspVO findNoteDetailRspVO) {