feat(note): 实现笔记发布功能并优化数据模型
- 新增笔记发布接口,支持图文和视频类型 - 引入分布式ID生成器和KV存储服务 - 修改笔记、频道、话题等实体类使用LocalDateTime - 添加频道-话题关联表及相应服务实现 - 更新数据库表结构,增加笔记内容UUID字段 - 完善笔记发布时的内容校验和异常处理 - 配置网关路由支持新的笔记服务路径 - 优化MyBatis Mapper扫描和Feign客户端配置
This commit is contained in:
@@ -16,6 +16,12 @@ spring:
|
|||||||
- Path=/user/**
|
- Path=/user/**
|
||||||
filters:
|
filters:
|
||||||
- StripPrefix=1
|
- StripPrefix=1
|
||||||
|
- id: note
|
||||||
|
uri: lb://han-note-note
|
||||||
|
predicates:
|
||||||
|
- Path=/note/**
|
||||||
|
filters:
|
||||||
|
- StripPrefix=1
|
||||||
data:
|
data:
|
||||||
redis:
|
redis:
|
||||||
database: 5 # Redis 数据库索引(默认为 0)
|
database: 5 # Redis 数据库索引(默认为 0)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.hanserwei.hannote.kv.api;
|
|||||||
import com.hanserwei.framework.common.response.Response;
|
import com.hanserwei.framework.common.response.Response;
|
||||||
import com.hanserwei.hannote.kv.constant.ApiConstants;
|
import com.hanserwei.hannote.kv.constant.ApiConstants;
|
||||||
import com.hanserwei.hannote.kv.dto.req.AddNoteContentReqDTO;
|
import com.hanserwei.hannote.kv.dto.req.AddNoteContentReqDTO;
|
||||||
|
import com.hanserwei.hannote.kv.dto.req.DeleteNoteContentReqDTO;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
@@ -19,6 +20,6 @@ public interface KeyValueFeignApi {
|
|||||||
Response<?> findNoteContent(@RequestBody AddNoteContentReqDTO addNoteContentReqDTO);
|
Response<?> findNoteContent(@RequestBody AddNoteContentReqDTO addNoteContentReqDTO);
|
||||||
|
|
||||||
@PostMapping(value = PREFIX + "/note/content/delete")
|
@PostMapping(value = PREFIX + "/note/content/delete")
|
||||||
Response<?> deleteNoteContent(@RequestBody AddNoteContentReqDTO addNoteContentReqDTO);
|
Response<?> deleteNoteContent(@RequestBody DeleteNoteContentReqDTO deleteNoteContentReqDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -13,8 +13,8 @@ import lombok.NoArgsConstructor;
|
|||||||
@Builder
|
@Builder
|
||||||
public class AddNoteContentReqDTO {
|
public class AddNoteContentReqDTO {
|
||||||
|
|
||||||
@NotNull(message = "笔记 ID 不能为空")
|
@NotNull(message = "笔记内容 UUID 不能为空")
|
||||||
private Long noteId;
|
private String uuid;
|
||||||
|
|
||||||
@NotBlank(message = "笔记内容不能为空")
|
@NotBlank(message = "笔记内容不能为空")
|
||||||
private String content;
|
private String content;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import lombok.NoArgsConstructor;
|
|||||||
@Builder
|
@Builder
|
||||||
public class DeleteNoteContentReqDTO {
|
public class DeleteNoteContentReqDTO {
|
||||||
|
|
||||||
@NotBlank(message = "笔记 ID 不能为空")
|
@NotBlank(message = "笔记 UUID 不能为空")
|
||||||
private String noteId;
|
private String uuid;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@ import lombok.NoArgsConstructor;
|
|||||||
@Builder
|
@Builder
|
||||||
public class FindNoteContentReqDTO {
|
public class FindNoteContentReqDTO {
|
||||||
|
|
||||||
@NotBlank(message = "笔记 ID 不能为空")
|
@NotBlank(message = "笔记 UUID 不能为空")
|
||||||
private String noteId;
|
private String uuid;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -27,12 +27,12 @@ public class NoteContentServiceImpl implements NoteContentService {
|
|||||||
@Override
|
@Override
|
||||||
public Response<?> addNoteContent(AddNoteContentReqDTO addNoteContentReqDTO) {
|
public Response<?> addNoteContent(AddNoteContentReqDTO addNoteContentReqDTO) {
|
||||||
// 笔记ID
|
// 笔记ID
|
||||||
Long noteId = addNoteContentReqDTO.getNoteId();
|
String noteId = addNoteContentReqDTO.getUuid();
|
||||||
// 笔记内容
|
// 笔记内容
|
||||||
String content = addNoteContentReqDTO.getContent();
|
String content = addNoteContentReqDTO.getContent();
|
||||||
|
|
||||||
NoteContentDO noteContent = NoteContentDO.builder()
|
NoteContentDO noteContent = NoteContentDO.builder()
|
||||||
.id(UUID.randomUUID())
|
.id(UUID.fromString(noteId))
|
||||||
.content(content)
|
.content(content)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ public class NoteContentServiceImpl implements NoteContentService {
|
|||||||
@Override
|
@Override
|
||||||
public Response<FindNoteContentRspDTO> findNoteContent(FindNoteContentReqDTO findNoteContentReqDTO) {
|
public Response<FindNoteContentRspDTO> findNoteContent(FindNoteContentReqDTO findNoteContentReqDTO) {
|
||||||
// 笔记ID
|
// 笔记ID
|
||||||
String noteId = findNoteContentReqDTO.getNoteId();
|
String noteId = findNoteContentReqDTO.getUuid();
|
||||||
Optional<NoteContentDO> optional = noteContentRepository.findById(UUID.fromString(noteId));
|
Optional<NoteContentDO> optional = noteContentRepository.findById(UUID.fromString(noteId));
|
||||||
if (optional.isEmpty()){
|
if (optional.isEmpty()){
|
||||||
throw new ApiException(ResponseCodeEnum.NOTE_CONTENT_NOT_FOUND);
|
throw new ApiException(ResponseCodeEnum.NOTE_CONTENT_NOT_FOUND);
|
||||||
@@ -60,7 +60,7 @@ public class NoteContentServiceImpl implements NoteContentService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Response<?> deleteNoteContent(DeleteNoteContentReqDTO deleteNoteContentReqDTO) {
|
public Response<?> deleteNoteContent(DeleteNoteContentReqDTO deleteNoteContentReqDTO) {
|
||||||
String noteId = deleteNoteContentReqDTO.getNoteId();
|
String noteId = deleteNoteContentReqDTO.getUuid();
|
||||||
noteContentRepository.deleteById(UUID.fromString(noteId));
|
noteContentRepository.deleteById(UUID.fromString(noteId));
|
||||||
return Response.success();
|
return Response.success();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,15 @@
|
|||||||
<artifactId>commons-pool2</artifactId>
|
<artifactId>commons-pool2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hanserwei</groupId>
|
||||||
|
<artifactId>han-note-kv-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.hanserwei</groupId>
|
||||||
|
<artifactId>han-note-distributed-id-generator-api</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package com.hanserwei.hannote.note.biz;
|
package com.hanserwei.hannote.note.biz;
|
||||||
|
|
||||||
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@MapperScan("com.hanserwei.hannote.note.biz.domain.mapper")
|
||||||
|
@EnableFeignClients(basePackages = "com.hanserwei.hannote")
|
||||||
public class HannoteNoteBizApplication {
|
public class HannoteNoteBizApplication {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(HannoteNoteBizApplication.class, args);
|
SpringApplication.run(HannoteNoteBizApplication.class, args);
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
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.PublishNoteReqVO;
|
||||||
|
import com.hanserwei.hannote.note.biz.service.NoteService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/note")
|
||||||
|
@Slf4j
|
||||||
|
public class NoteController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private NoteService noteService;
|
||||||
|
|
||||||
|
@PostMapping(value = "/publish")
|
||||||
|
@ApiOperationLog(description = "笔记发布")
|
||||||
|
public Response<?> publishNote(@Validated @RequestBody PublishNoteReqVO publishNoteReqVO) {
|
||||||
|
return noteService.publishNote(publishNoteReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,15 +4,18 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import java.util.Date;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 频道表
|
* 频道表
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@Builder
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@TableName(value = "t_channel")
|
@TableName(value = "t_channel")
|
||||||
@@ -33,13 +36,13 @@ public class ChannelDO {
|
|||||||
* 创建时间
|
* 创建时间
|
||||||
*/
|
*/
|
||||||
@TableField(value = "create_time")
|
@TableField(value = "create_time")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新时间
|
* 更新时间
|
||||||
*/
|
*/
|
||||||
@TableField(value = "update_time")
|
@TableField(value = "update_time")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 逻辑删除(0:未删除 1:已删除)
|
* 逻辑删除(0:未删除 1:已删除)
|
||||||
|
|||||||
@@ -4,15 +4,18 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import java.util.Date;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 频道-话题关联表
|
* 频道-话题关联表
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@Builder
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@TableName(value = "t_channel_topic_rel")
|
@TableName(value = "t_channel_topic_rel")
|
||||||
@@ -39,11 +42,11 @@ public class ChannelTopicRelDO {
|
|||||||
* 创建时间
|
* 创建时间
|
||||||
*/
|
*/
|
||||||
@TableField(value = "create_time")
|
@TableField(value = "create_time")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新时间
|
* 更新时间
|
||||||
*/
|
*/
|
||||||
@TableField(value = "update_time")
|
@TableField(value = "update_time")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
}
|
}
|
||||||
@@ -4,15 +4,18 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import java.util.Date;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 笔记表
|
* 笔记表
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@Builder
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@TableName(value = "t_note")
|
@TableName(value = "t_note")
|
||||||
@@ -63,7 +66,7 @@ public class NoteDO {
|
|||||||
* 类型(0:图文 1:视频)
|
* 类型(0:图文 1:视频)
|
||||||
*/
|
*/
|
||||||
@TableField(value = "`type`")
|
@TableField(value = "`type`")
|
||||||
private Byte type;
|
private Integer type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 笔记图片链接(逗号隔开)
|
* 笔记图片链接(逗号隔开)
|
||||||
@@ -81,23 +84,29 @@ public class NoteDO {
|
|||||||
* 可见范围(0:公开,所有人可见 1:仅对自己可见)
|
* 可见范围(0:公开,所有人可见 1:仅对自己可见)
|
||||||
*/
|
*/
|
||||||
@TableField(value = "visible")
|
@TableField(value = "visible")
|
||||||
private Byte visible;
|
private Integer visible;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建时间
|
* 创建时间
|
||||||
*/
|
*/
|
||||||
@TableField(value = "create_time")
|
@TableField(value = "create_time")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新时间
|
* 更新时间
|
||||||
*/
|
*/
|
||||||
@TableField(value = "update_time")
|
@TableField(value = "update_time")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 状态(0:待审核 1:正常展示 2:被删除(逻辑删除) 3:被下架)
|
* 状态(0:待审核 1:正常展示 2:被删除(逻辑删除) 3:被下架)
|
||||||
*/
|
*/
|
||||||
@TableField(value = "`status`")
|
@TableField(value = "`status`")
|
||||||
private Byte status;
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 笔记内容UUID
|
||||||
|
*/
|
||||||
|
@TableField(value = "content_uuid")
|
||||||
|
private String contentUuid;
|
||||||
}
|
}
|
||||||
@@ -4,15 +4,18 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import java.util.Date;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 话题表
|
* 话题表
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@Builder
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@TableName(value = "t_topic")
|
@TableName(value = "t_topic")
|
||||||
@@ -33,13 +36,13 @@ public class TopicDO {
|
|||||||
* 创建时间
|
* 创建时间
|
||||||
*/
|
*/
|
||||||
@TableField(value = "create_time")
|
@TableField(value = "create_time")
|
||||||
private Date createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新时间
|
* 更新时间
|
||||||
*/
|
*/
|
||||||
@TableField(value = "update_time")
|
@TableField(value = "update_time")
|
||||||
private Date updateTime;
|
private LocalDateTime updateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 逻辑删除(0:未删除 1:已删除)
|
* 逻辑删除(0:未删除 1:已删除)
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package com.hanserwei.hannote.note.biz.domain.mapper;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.hanserwei.hannote.note.biz.domain.dataobject.ChannelDO;
|
import com.hanserwei.hannote.note.biz.domain.dataobject.ChannelDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
public interface ChannelDOMapper extends BaseMapper<ChannelDO> {
|
public interface ChannelDOMapper extends BaseMapper<ChannelDO> {
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,8 @@ package com.hanserwei.hannote.note.biz.domain.mapper;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.hanserwei.hannote.note.biz.domain.dataobject.ChannelTopicRelDO;
|
import com.hanserwei.hannote.note.biz.domain.dataobject.ChannelTopicRelDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
public interface ChannelTopicRelDOMapper extends BaseMapper<ChannelTopicRelDO> {
|
public interface ChannelTopicRelDOMapper extends BaseMapper<ChannelTopicRelDO> {
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,8 @@ package com.hanserwei.hannote.note.biz.domain.mapper;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.hanserwei.hannote.note.biz.domain.dataobject.NoteDO;
|
import com.hanserwei.hannote.note.biz.domain.dataobject.NoteDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
public interface NoteDOMapper extends BaseMapper<NoteDO> {
|
public interface NoteDOMapper extends BaseMapper<NoteDO> {
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,8 @@ package com.hanserwei.hannote.note.biz.domain.mapper;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.hanserwei.hannote.note.biz.domain.dataobject.TopicDO;
|
import com.hanserwei.hannote.note.biz.domain.dataobject.TopicDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
public interface TopicDOMapper extends BaseMapper<TopicDO> {
|
public interface TopicDOMapper extends BaseMapper<TopicDO> {
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,8 @@ public enum ResponseCodeEnum implements BaseExceptionInterface {
|
|||||||
PARAM_NOT_VALID("NOTE-10001", "参数错误"),
|
PARAM_NOT_VALID("NOTE-10001", "参数错误"),
|
||||||
|
|
||||||
// ----------- 业务异常状态码 -----------
|
// ----------- 业务异常状态码 -----------
|
||||||
|
NOTE_TYPE_ERROR("NOTE-20000", "未知的笔记类型"),
|
||||||
|
NOTE_PUBLISH_FAIL("NOTE-20001", "笔记发布失败"),
|
||||||
;
|
;
|
||||||
|
|
||||||
// 异常码
|
// 异常码
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Builder
|
||||||
|
public class PublishNoteReqVO {
|
||||||
|
|
||||||
|
@NotNull(message = "笔记类型不能为空")
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
private List<String> imgUris;
|
||||||
|
|
||||||
|
private String videoUri;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
private Long topicId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.hanserwei.hannote.note.biz.rpc;
|
||||||
|
|
||||||
|
import com.hanserwei.hannote.distributed.id.generator.api.DistributedIdGeneratorFeignApi;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class DistributedIdGeneratorRpcService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DistributedIdGeneratorFeignApi distributedIdGeneratorFeignApi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成雪花算法 ID
|
||||||
|
*
|
||||||
|
* @return 雪花算法 ID
|
||||||
|
*/
|
||||||
|
public String getSnowflakeId() {
|
||||||
|
return distributedIdGeneratorFeignApi.getSnowflakeId("test");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package com.hanserwei.hannote.note.biz.rpc;
|
||||||
|
|
||||||
|
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 jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class KeyValueRpcService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private KeyValueFeignApi keyValueFeignApi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存笔记内容
|
||||||
|
*
|
||||||
|
* @param uuid 笔记UUID
|
||||||
|
* @param content 笔记内容
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
public boolean saveNoteContent(String uuid, String content) {
|
||||||
|
AddNoteContentReqDTO addNoteContentReqDTO = new AddNoteContentReqDTO();
|
||||||
|
addNoteContentReqDTO.setUuid(uuid);
|
||||||
|
addNoteContentReqDTO.setContent(content);
|
||||||
|
|
||||||
|
Response<?> response = keyValueFeignApi.addNoteContent(addNoteContentReqDTO);
|
||||||
|
|
||||||
|
return Objects.nonNull(response) && response.isSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除笔记内容
|
||||||
|
*
|
||||||
|
* @param uuid 笔记UUID
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
public boolean deleteNoteContent(String uuid) {
|
||||||
|
DeleteNoteContentReqDTO deleteNoteContentReqDTO = new DeleteNoteContentReqDTO();
|
||||||
|
deleteNoteContentReqDTO.setUuid(uuid);
|
||||||
|
|
||||||
|
Response<?> response = keyValueFeignApi.deleteNoteContent(deleteNoteContentReqDTO);
|
||||||
|
|
||||||
|
return Objects.nonNull(response) && response.isSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.hanserwei.hannote.note.biz.service;
|
||||||
|
|
||||||
|
import com.hanserwei.hannote.note.biz.domain.dataobject.ChannelDO;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
public interface ChannelDOService extends IService<ChannelDO>{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.hanserwei.hannote.note.biz.service;
|
||||||
|
|
||||||
|
import com.hanserwei.hannote.note.biz.domain.dataobject.ChannelTopicRelDO;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
public interface ChannelTopicRelDOService extends IService<ChannelTopicRelDO>{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
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.PublishNoteReqVO;
|
||||||
|
|
||||||
|
public interface NoteService extends IService<NoteDO> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 笔记发布
|
||||||
|
* @param publishNoteReqVO 笔记发布请求
|
||||||
|
* @return 笔记发布结果
|
||||||
|
*/
|
||||||
|
Response<?> publishNote(PublishNoteReqVO publishNoteReqVO);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.hanserwei.hannote.note.biz.service;
|
||||||
|
|
||||||
|
import com.hanserwei.hannote.note.biz.domain.dataobject.TopicDO;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
public interface TopicDOService extends IService<TopicDO>{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.hanserwei.hannote.note.biz.service.impl;
|
||||||
|
|
||||||
|
import com.hanserwei.hannote.note.biz.service.ChannelDOService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.hanserwei.hannote.note.biz.domain.dataobject.ChannelDO;
|
||||||
|
import com.hanserwei.hannote.note.biz.domain.mapper.ChannelDOMapper;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ChannelDOServiceImpl extends ServiceImpl<ChannelDOMapper, ChannelDO> implements ChannelDOService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.hanserwei.hannote.note.biz.service.impl;
|
||||||
|
|
||||||
|
import com.hanserwei.hannote.note.biz.service.ChannelTopicRelDOService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.hanserwei.hannote.note.biz.domain.mapper.ChannelTopicRelDOMapper;
|
||||||
|
import com.hanserwei.hannote.note.biz.domain.dataobject.ChannelTopicRelDO;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ChannelTopicRelDOServiceImpl extends ServiceImpl<ChannelTopicRelDOMapper, ChannelTopicRelDO> implements ChannelTopicRelDOService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
package com.hanserwei.hannote.note.biz.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
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.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.PublishNoteReqVO;
|
||||||
|
import com.hanserwei.hannote.note.biz.rpc.DistributedIdGeneratorRpcService;
|
||||||
|
import com.hanserwei.hannote.note.biz.rpc.KeyValueRpcService;
|
||||||
|
import com.hanserwei.hannote.note.biz.service.NoteService;
|
||||||
|
import com.hanserwei.hannote.note.biz.service.TopicDOService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class NoteServiceImpl extends ServiceImpl<NoteDOMapper, NoteDO> implements NoteService {
|
||||||
|
@Resource
|
||||||
|
private DistributedIdGeneratorRpcService distributedIdGeneratorRpcService;
|
||||||
|
@Resource
|
||||||
|
private KeyValueRpcService keyValueRpcService;
|
||||||
|
@Resource
|
||||||
|
private TopicDOService topicDOService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response<?> publishNote(PublishNoteReqVO publishNoteReqVO) {
|
||||||
|
// 笔记类型
|
||||||
|
Integer type = publishNoteReqVO.getType();
|
||||||
|
|
||||||
|
// 获取对应的枚举类型
|
||||||
|
NoteTypeEnum noteTypeEnum = NoteTypeEnum.valueOf(type);
|
||||||
|
|
||||||
|
// 若非图文或视频则抛异常
|
||||||
|
if (Objects.isNull(noteTypeEnum)) {
|
||||||
|
throw new ApiException(ResponseCodeEnum.NOTE_TYPE_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
String imgUris = null;
|
||||||
|
// 笔记内容是否为空,默认为空,即true
|
||||||
|
boolean isContentEmpty = true;
|
||||||
|
String videoUri = null;
|
||||||
|
switch (noteTypeEnum) {
|
||||||
|
case IMAGE_TEXT -> {
|
||||||
|
List<String> imgUriList = publishNoteReqVO.getImgUris();
|
||||||
|
//校验图片是否为空
|
||||||
|
Preconditions.checkArgument(CollUtil.isNotEmpty(imgUriList), "笔记图片不能为空!");
|
||||||
|
//校验图片数目
|
||||||
|
Preconditions.checkArgument(imgUriList.size() <= 8, "图片不能超过8张!");
|
||||||
|
//把图片uri拼接成字符串,逗号隔开
|
||||||
|
imgUris = String.join(",", imgUriList);
|
||||||
|
}
|
||||||
|
case VIDEO -> {
|
||||||
|
videoUri = publishNoteReqVO.getVideoUri();
|
||||||
|
//校验视频是否为空
|
||||||
|
Preconditions.checkArgument(StringUtils.isNoneBlank(videoUri), "笔记视频不能为空!");
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RPC:调用分布式ID生成服务,生成笔记ID
|
||||||
|
String snowflakeId = distributedIdGeneratorRpcService.getSnowflakeId();
|
||||||
|
// 笔记内容UUID
|
||||||
|
String contentUuid = null;
|
||||||
|
// 笔记内容
|
||||||
|
String content = publishNoteReqVO.getContent();
|
||||||
|
// 若用户填写了笔记内容,则调用KV服务
|
||||||
|
if (StringUtils.isNotBlank(content)) {
|
||||||
|
isContentEmpty = false;
|
||||||
|
// 生成笔记内容UUID
|
||||||
|
contentUuid = UUID.randomUUID().toString();
|
||||||
|
// RPC:调用KV服务,保存笔记内容
|
||||||
|
boolean isSaveSuccess = keyValueRpcService.saveNoteContent(contentUuid, content);
|
||||||
|
// 若保存笔记内容失败,则抛异常
|
||||||
|
if (!isSaveSuccess) {
|
||||||
|
throw new ApiException(ResponseCodeEnum.NOTE_PUBLISH_FAIL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 话题
|
||||||
|
Long topicId = publishNoteReqVO.getTopicId();
|
||||||
|
String topicName = null;
|
||||||
|
if (Objects.nonNull(topicId)) {
|
||||||
|
//获取话题名称
|
||||||
|
topicName = topicDOService.getById(topicId).getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发布者ID
|
||||||
|
Long creatorId = LoginUserContextHolder.getUserId();
|
||||||
|
|
||||||
|
// 构建笔记对象
|
||||||
|
NoteDO noteDO = NoteDO.builder()
|
||||||
|
.id(Long.valueOf(snowflakeId))
|
||||||
|
.isContentEmpty(isContentEmpty)
|
||||||
|
.creatorId(creatorId)
|
||||||
|
.imgUris(imgUris)
|
||||||
|
.title(publishNoteReqVO.getTitle())
|
||||||
|
.topicId(publishNoteReqVO.getTopicId())
|
||||||
|
.topicName(topicName)
|
||||||
|
.type(type)
|
||||||
|
.visible(NoteVisibleEnum.PUBLIC.getCode())
|
||||||
|
.createTime(LocalDateTime.now())
|
||||||
|
.updateTime(LocalDateTime.now())
|
||||||
|
.status(NoteStatusEnum.NORMAL.getCode())
|
||||||
|
.isTop(Boolean.FALSE)
|
||||||
|
.videoUri(videoUri)
|
||||||
|
.contentUuid(contentUuid)
|
||||||
|
.build();
|
||||||
|
try {
|
||||||
|
boolean isSaveSuccess = this.save(noteDO);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("保存笔记失败!", e);
|
||||||
|
// RPC:调用KV服务,删除笔记内容
|
||||||
|
if (StringUtils.isNotBlank(contentUuid)) {
|
||||||
|
keyValueRpcService.deleteNoteContent(contentUuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Response.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.hanserwei.hannote.note.biz.service.impl;
|
||||||
|
|
||||||
|
import com.hanserwei.hannote.note.biz.service.TopicDOService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.hanserwei.hannote.note.biz.domain.dataobject.TopicDO;
|
||||||
|
import com.hanserwei.hannote.note.biz.domain.mapper.TopicDOMapper;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class TopicDOServiceImpl extends ServiceImpl<TopicDOMapper, TopicDO> implements TopicDOService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -18,10 +18,11 @@
|
|||||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
||||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
|
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
|
||||||
<result column="status" jdbcType="TINYINT" property="status" />
|
<result column="status" jdbcType="TINYINT" property="status" />
|
||||||
|
<result column="content_uuid" jdbcType="VARCHAR" property="contentUuid" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
<!--@mbg.generated-->
|
<!--@mbg.generated-->
|
||||||
id, title, is_content_empty, creator_id, topic_id, topic_name, is_top, `type`, img_uris,
|
id, title, is_content_empty, creator_id, topic_id, topic_name, is_top, `type`, img_uris,
|
||||||
video_uri, visible, create_time, update_time, `status`
|
video_uri, visible, create_time, update_time, `status`, content_uuid
|
||||||
</sql>
|
</sql>
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -15,3 +15,12 @@ VALUES (1, 1, 1, now(), now(), b'0');
|
|||||||
|
|
||||||
INSERT INTO `t_role_permission_rel` (`id`, `role_id`, `permission_id`, `create_time`, `update_time`, `is_deleted`)
|
INSERT INTO `t_role_permission_rel` (`id`, `role_id`, `permission_id`, `create_time`, `update_time`, `is_deleted`)
|
||||||
VALUES (2, 1, 2, now(), now(), b'0');
|
VALUES (2, 1, 2, now(), now(), b'0');
|
||||||
|
|
||||||
|
INSERT INTO `han_note`.`t_channel` (`name`, `create_time`, `update_time`, `is_deleted`) VALUES ('美食', now(), now(), 0);
|
||||||
|
INSERT INTO `han_note`.`t_channel` (`name`, `create_time`, `update_time`, `is_deleted`) VALUES ('娱乐', now(), now(), 0);
|
||||||
|
|
||||||
|
INSERT INTO `han_note`.`t_topic` (`name`, `create_time`, `update_time`, `is_deleted`) VALUES ('高分美剧推荐', now(), now(), 0);
|
||||||
|
INSERT INTO `han_note`.`t_topic` (`name`, `create_time`, `update_time`, `is_deleted`) VALUES ('下饭综艺推荐', now(), now(), 0);
|
||||||
|
|
||||||
|
INSERT INTO `han_note`.`t_channel_topic_rel` (`channel_id`, `topic_id`, `create_time`, `update_time`) VALUES (2, 1, now(), now());
|
||||||
|
INSERT INTO `han_note`.`t_channel_topic_rel` (`channel_id`, `topic_id`, `create_time`, `update_time`) VALUES (2, 2, now(), now());
|
||||||
|
|||||||
@@ -146,4 +146,6 @@ CREATE TABLE `t_note`
|
|||||||
KEY `idx_status` (`status`)
|
KEY `idx_status` (`status`)
|
||||||
) ENGINE = InnoDB
|
) ENGINE = InnoDB
|
||||||
DEFAULT CHARSET = utf8mb4
|
DEFAULT CHARSET = utf8mb4
|
||||||
COLLATE = utf8mb4_unicode_ci COMMENT ='笔记表';
|
COLLATE = utf8mb4_unicode_ci COMMENT ='笔记表';
|
||||||
|
|
||||||
|
ALTER table t_note add column `content_uuid` varchar(36) DEFAULT '' COMMENT '笔记内容UUID';
|
||||||
|
|||||||
Reference in New Issue
Block a user