feat(note): 新增笔记详情查询功能
- 新增笔记详情请求VO类 FindNoteDetailReqVO - 新增笔记详情响应VO类 FindNoteDetailRspVO - KV服务Feign接口新增查询笔记内容方法 - KeyValueRpcService新增findNoteContent方法实现 - NoteController新增笔记详情查询接口 - NoteService接口及实现类新增findNoteDetail方法 - 新增RedisKeyConstants常量类用于构建笔记详情缓存KEY - 新增ResponseCodeEnum枚举值用于笔记相关异常码 - 新增ThreadPoolConfig配置类定义异步线程池 - 新增UserRpcService用于调用用户服务查询用户信息 - 笔记详情接口支持多级缓存(本地缓存Caffeine+Redis) - 笔记详情查询增加可见性校验逻辑 - pom.xml新增用户服务api依赖和Caffeine依赖 - UserFeignApi新增根据ID查询用户信息接口
This commit is contained in:
@@ -4,6 +4,8 @@ import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.hannote.kv.constant.ApiConstants;
|
||||
import com.hanserwei.hannote.kv.dto.req.AddNoteContentReqDTO;
|
||||
import com.hanserwei.hannote.kv.dto.req.DeleteNoteContentReqDTO;
|
||||
import com.hanserwei.hannote.kv.dto.req.FindNoteContentReqDTO;
|
||||
import com.hanserwei.hannote.kv.dto.resp.FindNoteContentRspDTO;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -17,7 +19,7 @@ public interface KeyValueFeignApi {
|
||||
Response<?> addNoteContent(@RequestBody AddNoteContentReqDTO addNoteContentReqDTO);
|
||||
|
||||
@PostMapping(value = PREFIX + "/note/content/find")
|
||||
Response<?> findNoteContent(@RequestBody AddNoteContentReqDTO addNoteContentReqDTO);
|
||||
Response<FindNoteContentRspDTO> findNoteContent(@RequestBody FindNoteContentReqDTO findNoteContentReqDTO);
|
||||
|
||||
@PostMapping(value = PREFIX + "/note/content/delete")
|
||||
Response<?> deleteNoteContent(@RequestBody DeleteNoteContentReqDTO deleteNoteContentReqDTO);
|
||||
|
||||
@@ -100,6 +100,18 @@
|
||||
<groupId>com.hanserwei</groupId>
|
||||
<artifactId>han-note-distributed-id-generator-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.hanserwei</groupId>
|
||||
<artifactId>han-note-user-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Caffeine 本地缓存 -->
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.hanserwei.hannote.note.biz.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
@Configuration
|
||||
public class ThreadPoolConfig {
|
||||
|
||||
@Bean(name = "noteTaskExecutor")
|
||||
public ThreadPoolTaskExecutor taskExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
// 核心线程数
|
||||
executor.setCorePoolSize(10);
|
||||
// 最大线程数
|
||||
executor.setMaxPoolSize(50);
|
||||
// 队列容量
|
||||
executor.setQueueCapacity(200);
|
||||
// 线程活跃时间(秒)
|
||||
executor.setKeepAliveSeconds(30);
|
||||
// 线程名前缀
|
||||
executor.setThreadNamePrefix("NoteExecutor-");
|
||||
|
||||
// 拒绝策略:由调用线程处理(一般为主线程)
|
||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
|
||||
// 等待所有任务结束后再关闭线程池
|
||||
executor.setWaitForTasksToCompleteOnShutdown(true);
|
||||
// 设置等待时间,如果超过这个时间还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是被没有完成的任务阻塞
|
||||
executor.setAwaitTerminationSeconds(60);
|
||||
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.hanserwei.hannote.note.biz.constant;
|
||||
|
||||
public class RedisKeyConstants {
|
||||
|
||||
/**
|
||||
* 笔记详情 KEY 前缀
|
||||
*/
|
||||
public static final String NOTE_DETAIL_KEY = "note:detail:";
|
||||
|
||||
|
||||
/**
|
||||
* 构建完整的笔记详情 KEY
|
||||
* @param noteId 笔记ID
|
||||
* @return 笔记详情 KEY
|
||||
*/
|
||||
public static String buildNoteDetailKey(Long noteId) {
|
||||
return NOTE_DETAIL_KEY + noteId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package com.hanserwei.hannote.note.biz.controller;
|
||||
|
||||
import com.hanserwei.framework.biz.operationlog.aspect.ApiOperationLog;
|
||||
import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.hannote.note.biz.model.vo.FindNoteDetailReqVO;
|
||||
import com.hanserwei.hannote.note.biz.model.vo.FindNoteDetailRspVO;
|
||||
import com.hanserwei.hannote.note.biz.model.vo.PublishNoteReqVO;
|
||||
import com.hanserwei.hannote.note.biz.service.NoteService;
|
||||
import jakarta.annotation.Resource;
|
||||
@@ -26,4 +28,10 @@ public class NoteController {
|
||||
return noteService.publishNote(publishNoteReqVO);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/detail")
|
||||
@ApiOperationLog(description = "笔记详情")
|
||||
public Response<FindNoteDetailRspVO> findNoteDetail(@Validated @RequestBody FindNoteDetailReqVO findNoteDetailReqVO) {
|
||||
return noteService.findNoteDetail(findNoteDetailReqVO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package com.hanserwei.hannote.note.biz.domain.dataobject;
|
||||
|
||||
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 com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -15,6 +15,9 @@ public enum ResponseCodeEnum implements BaseExceptionInterface {
|
||||
// ----------- 业务异常状态码 -----------
|
||||
NOTE_TYPE_ERROR("NOTE-20000", "未知的笔记类型"),
|
||||
NOTE_PUBLISH_FAIL("NOTE-20001", "笔记发布失败"),
|
||||
NOTE_NOT_FOUND("NOTE-20002", "笔记不存在"),
|
||||
NOTE_PRIVATE("NOTE-20003", "作者已将该笔记设置为仅自己可见"),
|
||||
;
|
||||
;
|
||||
|
||||
// 异常码
|
||||
|
||||
@@ -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 FindNoteDetailReqVO {
|
||||
|
||||
@NotNull(message = "笔记 ID 不能为空")
|
||||
private Long id;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.hanserwei.hannote.note.biz.model.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class FindNoteDetailRspVO {
|
||||
|
||||
private Long id;
|
||||
|
||||
private Integer type;
|
||||
|
||||
private String title;
|
||||
|
||||
private String content;
|
||||
|
||||
private List<String> imgUris;
|
||||
|
||||
private Long topicId;
|
||||
|
||||
private String topicName;
|
||||
|
||||
private Long creatorId;
|
||||
|
||||
private String creatorName;
|
||||
|
||||
private String avatar;
|
||||
|
||||
private String videoUri;
|
||||
|
||||
/**
|
||||
* 编辑时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 是否可见
|
||||
*/
|
||||
private Integer visible;
|
||||
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.hannote.kv.api.KeyValueFeignApi;
|
||||
import com.hanserwei.hannote.kv.dto.req.AddNoteContentReqDTO;
|
||||
import com.hanserwei.hannote.kv.dto.req.DeleteNoteContentReqDTO;
|
||||
import com.hanserwei.hannote.kv.dto.req.FindNoteContentReqDTO;
|
||||
import com.hanserwei.hannote.kv.dto.resp.FindNoteContentRspDTO;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -47,4 +49,23 @@ public class KeyValueRpcService {
|
||||
return Objects.nonNull(response) && response.isSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询笔记内容
|
||||
*
|
||||
* @param uuid 笔记UUID
|
||||
* @return 笔记内容
|
||||
*/
|
||||
public String findNoteContent(String uuid) {
|
||||
FindNoteContentReqDTO findNoteContentReqDTO = new FindNoteContentReqDTO();
|
||||
findNoteContentReqDTO.setUuid(uuid);
|
||||
|
||||
Response<FindNoteContentRspDTO> response = keyValueFeignApi.findNoteContent(findNoteContentReqDTO);
|
||||
|
||||
if (Objects.isNull(response) || !response.isSuccess() || Objects.isNull(response.getData())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return response.getData().getContent();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.hanserwei.hannote.note.biz.rpc;
|
||||
|
||||
import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.hannote.user.api.UserFeignApi;
|
||||
import com.hanserwei.hannote.user.dto.req.FindUserByIdReqDTO;
|
||||
import com.hanserwei.hannote.user.dto.resp.FindUserByIdRspDTO;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Component
|
||||
public class UserRpcService {
|
||||
@Resource
|
||||
private UserFeignApi userFeignApi;
|
||||
|
||||
/**
|
||||
* 查询用户信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 用户信息
|
||||
*/
|
||||
public FindUserByIdRspDTO findById(Long userId) {
|
||||
FindUserByIdReqDTO findUserByIdReqDTO = new FindUserByIdReqDTO();
|
||||
findUserByIdReqDTO.setId(userId);
|
||||
|
||||
Response<FindUserByIdRspDTO> response = userFeignApi.findById(findUserByIdReqDTO);
|
||||
|
||||
if (Objects.isNull(response) || !response.isSuccess()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return response.getData();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.hanserwei.hannote.note.biz.service;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.hannote.note.biz.domain.dataobject.NoteDO;
|
||||
import com.hanserwei.hannote.note.biz.model.vo.FindNoteDetailReqVO;
|
||||
import com.hanserwei.hannote.note.biz.model.vo.FindNoteDetailRspVO;
|
||||
import com.hanserwei.hannote.note.biz.model.vo.PublishNoteReqVO;
|
||||
|
||||
public interface NoteService extends IService<NoteDO> {
|
||||
@@ -14,4 +16,11 @@ public interface NoteService extends IService<NoteDO> {
|
||||
*/
|
||||
Response<?> publishNote(PublishNoteReqVO publishNoteReqVO);
|
||||
|
||||
/**
|
||||
* 笔记详情
|
||||
* @param findNoteDetailReqVO 笔记详情请求
|
||||
* @return 笔记详情结果
|
||||
*/
|
||||
Response<FindNoteDetailRspVO> findNoteDetail(FindNoteDetailReqVO findNoteDetailReqVO);
|
||||
|
||||
}
|
||||
@@ -1,31 +1,45 @@
|
||||
package com.hanserwei.hannote.note.biz.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.hanserwei.framework.biz.context.holder.LoginUserContextHolder;
|
||||
import com.hanserwei.framework.common.exception.ApiException;
|
||||
import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.framework.common.utils.JsonUtils;
|
||||
import com.hanserwei.hannote.note.biz.constant.RedisKeyConstants;
|
||||
import com.hanserwei.hannote.note.biz.domain.dataobject.NoteDO;
|
||||
import com.hanserwei.hannote.note.biz.domain.mapper.NoteDOMapper;
|
||||
import com.hanserwei.hannote.note.biz.enums.NoteStatusEnum;
|
||||
import com.hanserwei.hannote.note.biz.enums.NoteTypeEnum;
|
||||
import com.hanserwei.hannote.note.biz.enums.NoteVisibleEnum;
|
||||
import com.hanserwei.hannote.note.biz.enums.ResponseCodeEnum;
|
||||
import com.hanserwei.hannote.note.biz.model.vo.FindNoteDetailReqVO;
|
||||
import com.hanserwei.hannote.note.biz.model.vo.FindNoteDetailRspVO;
|
||||
import com.hanserwei.hannote.note.biz.model.vo.PublishNoteReqVO;
|
||||
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.NoteService;
|
||||
import com.hanserwei.hannote.note.biz.service.TopicDOService;
|
||||
import com.hanserwei.hannote.user.dto.resp.FindUserByIdRspDTO;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -36,6 +50,22 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
|
||||
private KeyValueRpcService keyValueRpcService;
|
||||
@Resource
|
||||
private TopicDOService topicDOService;
|
||||
@Resource
|
||||
private UserRpcService userRpcService;
|
||||
@Resource(name = "noteTaskExecutor")
|
||||
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
||||
@Resource
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
/**
|
||||
* 笔记详情本地缓存
|
||||
*/
|
||||
@SuppressWarnings("NullableProblems")
|
||||
private static final Cache<Long, String> LOCAL_CACHE = Caffeine.newBuilder()
|
||||
.initialCapacity(10000) // 设置初始容量为 10000 个条目
|
||||
.maximumSize(10000) // 设置缓存的最大容量为 10000 个条目
|
||||
.expireAfterWrite(1, TimeUnit.HOURS) // 设置缓存条目在写入后 1 小时过期
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public Response<?> publishNote(PublishNoteReqVO publishNoteReqVO) {
|
||||
@@ -127,9 +157,141 @@ public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implement
|
||||
log.error("保存笔记失败!", e);
|
||||
// RPC:调用KV服务,删除笔记内容
|
||||
if (StringUtils.isNotBlank(contentUuid)) {
|
||||
keyValueRpcService.deleteNoteContent(contentUuid);
|
||||
boolean res = keyValueRpcService.deleteNoteContent(contentUuid);
|
||||
if (!res) {
|
||||
log.error("删除笔记内容失败!");
|
||||
}
|
||||
}
|
||||
}
|
||||
return Response.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response<FindNoteDetailRspVO> findNoteDetail(FindNoteDetailReqVO findNoteDetailReqVO) {
|
||||
// 查询笔记ID
|
||||
Long noteId = findNoteDetailReqVO.getId();
|
||||
|
||||
// 当前登录用户
|
||||
Long userId = LoginUserContextHolder.getUserId();
|
||||
|
||||
// 先从本地缓存中查询
|
||||
String findNoteDetailRspVOStrLocalCache = LOCAL_CACHE.getIfPresent(noteId);
|
||||
if (StringUtils.isNotBlank(findNoteDetailRspVOStrLocalCache)) {
|
||||
FindNoteDetailRspVO findNoteDetailRspVO = JsonUtils.parseObject(findNoteDetailRspVOStrLocalCache, FindNoteDetailRspVO.class);
|
||||
log.info("==> 笔记详情命中了本地缓存;{}", findNoteDetailRspVOStrLocalCache);
|
||||
// 可见性校验
|
||||
checkNoteVisibleFromVO(userId, findNoteDetailRspVO);
|
||||
return Response.success(findNoteDetailRspVO);
|
||||
}
|
||||
|
||||
// 从Redis缓存中获取
|
||||
String noteDetailRedisKey = RedisKeyConstants.buildNoteDetailKey(noteId);
|
||||
String noteDetailJson = redisTemplate.opsForValue().get(noteDetailRedisKey);
|
||||
// 若缓存中有该笔记的数据,则直接返回
|
||||
if (StringUtils.isNotBlank(noteDetailJson)) {
|
||||
FindNoteDetailRspVO findNoteDetailRspVO = JsonUtils.parseObject(noteDetailJson, FindNoteDetailRspVO.class);
|
||||
// 异步线程中将用户信息存入本地缓存
|
||||
threadPoolTaskExecutor.submit(() -> {
|
||||
// 写入本地缓存
|
||||
LOCAL_CACHE.put(noteId,
|
||||
Objects.isNull(findNoteDetailRspVO) ? "null" : JsonUtils.toJsonString(findNoteDetailRspVO));
|
||||
});
|
||||
// 可见性校验
|
||||
checkNoteVisibleFromVO(userId, findNoteDetailRspVO);
|
||||
|
||||
return Response.success(findNoteDetailRspVO);
|
||||
}
|
||||
|
||||
// 查询笔记
|
||||
NoteDO noteDO = this.getOne(new LambdaQueryWrapper<>(NoteDO.class)
|
||||
.eq(NoteDO::getId, noteId)
|
||||
.eq(NoteDO::getStatus, 1));
|
||||
|
||||
// 若笔记不存在,则抛异常
|
||||
if (Objects.isNull(noteDO)){
|
||||
threadPoolTaskExecutor.execute(() -> {
|
||||
// 防止缓存穿透,将空数据存入 Redis 缓存 (过期时间不宜设置过长)
|
||||
// 保底1分钟 + 随机秒数
|
||||
long expireSeconds = 60 + RandomUtil.randomInt(60);
|
||||
redisTemplate.opsForValue().set(noteDetailRedisKey, "null", expireSeconds, TimeUnit.SECONDS);
|
||||
});
|
||||
throw new ApiException(ResponseCodeEnum.NOTE_NOT_FOUND);
|
||||
}
|
||||
|
||||
// 可见性校验
|
||||
Integer visible = noteDO.getVisible();
|
||||
checkNoteVisible(visible, userId, noteDO.getCreatorId());
|
||||
|
||||
// RPC调用用户服务,获取用户信息
|
||||
Long creatorId = noteDO.getCreatorId();
|
||||
FindUserByIdRspDTO findUserByIdRspDTO = userRpcService.findById(creatorId);
|
||||
|
||||
// RPC: 调用 K-V 存储服务获取内容
|
||||
String content = null;
|
||||
if (Objects.equals(noteDO.getIsContentEmpty(), Boolean.FALSE)) {
|
||||
content = keyValueRpcService.findNoteContent(noteDO.getContentUuid());
|
||||
}
|
||||
|
||||
// 笔记类型
|
||||
Integer noteType = noteDO.getType();
|
||||
// 图文笔记图片链接(字符串)
|
||||
String imgUrisStr = noteDO.getImgUris();
|
||||
// 图文笔记图片链接(集合)
|
||||
List<String> 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();
|
||||
// 异步线程中将笔记详情存入 Redis
|
||||
threadPoolTaskExecutor.submit(() -> {
|
||||
String noteDetailJson1 = JsonUtils.toJsonString(findNoteDetailRspVO);
|
||||
// 过期时间(保底1天 + 随机秒数,将缓存过期时间打散,防止同一时间大量缓存失效,导致数据库压力太大)
|
||||
long expireSeconds = 60*60*24 + RandomUtil.randomInt(60*60*24);
|
||||
redisTemplate.opsForValue().set(noteDetailRedisKey, noteDetailJson1, expireSeconds, TimeUnit.SECONDS);
|
||||
});
|
||||
return Response.success(findNoteDetailRspVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验笔记的可见性
|
||||
* @param visible 是否可见
|
||||
* @param userId 当前用户 ID
|
||||
* @param creatorId 笔记创建者
|
||||
*/
|
||||
private void checkNoteVisible(Integer visible, Long userId, Long creatorId) {
|
||||
if (Objects.equals(visible, NoteVisibleEnum.PRIVATE.getCode())
|
||||
&& !Objects.equals(userId, creatorId)) { // 仅自己可见, 并且访问用户为笔记创建者才能访问,非本人则抛出异常
|
||||
throw new ApiException(ResponseCodeEnum.NOTE_PRIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验笔记的可见性(针对 VO 实体类)
|
||||
* @param userId 当前用户 ID
|
||||
* @param findNoteDetailRspVO 笔记详情VO类
|
||||
*/
|
||||
private void checkNoteVisibleFromVO(Long userId, FindNoteDetailRspVO findNoteDetailRspVO) {
|
||||
if (Objects.nonNull(findNoteDetailRspVO)) {
|
||||
Integer visible = findNoteDetailRspVO.getVisible();
|
||||
checkNoteVisible(visible, userId, findNoteDetailRspVO.getCreatorId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ package com.hanserwei.hannote.user.api;
|
||||
import com.hanserwei.framework.common.response.Response;
|
||||
import com.hanserwei.hannote.user.constant.ApiConstants;
|
||||
import com.hanserwei.hannote.user.dto.req.FindUserByEmailReqDTO;
|
||||
import com.hanserwei.hannote.user.dto.req.FindUserByIdReqDTO;
|
||||
import com.hanserwei.hannote.user.dto.req.RegisterUserReqDTO;
|
||||
import com.hanserwei.hannote.user.dto.req.UpdateUserPasswordReqDTO;
|
||||
import com.hanserwei.hannote.user.dto.resp.FindUserByEmailRspDTO;
|
||||
import com.hanserwei.hannote.user.dto.resp.FindUserByIdRspDTO;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -42,4 +44,12 @@ public interface UserFeignApi {
|
||||
@PostMapping(value = PREFIX + "/password/update")
|
||||
Response<?> updatePassword(@RequestBody UpdateUserPasswordReqDTO updateUserPasswordReqDTO);
|
||||
|
||||
/**
|
||||
* 根据用户 ID 查询用户信息
|
||||
*
|
||||
* @param findUserByIdReqDTO 查询信息请求
|
||||
* @return 响应
|
||||
*/
|
||||
@PostMapping(value = PREFIX + "/findById")
|
||||
Response<FindUserByIdRspDTO> findById(@RequestBody FindUserByIdReqDTO findUserByIdReqDTO);
|
||||
}
|
||||
Reference in New Issue
Block a user