refactor: 基于 novel 项目 & Spring Cloud 2022 & Spring Cloud Alibaba 2022 重构

This commit is contained in:
xiongxiaoyang
2023-03-30 16:15:56 +08:00
parent d68ce51c82
commit 3d098eea5e
505 changed files with 14127 additions and 24067 deletions

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>novel-book</artifactId>
<groupId>io.github.xxyopen</groupId>
<version>2.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>novel-book-api</artifactId>
<dependencies>
<dependency>
<groupId>io.github.xxyopen</groupId>
<artifactId>novel-common</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,76 @@
package io.github.xxyopen.novel.book.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* 小说发布 请求DTO
*
* @author xiongxiaoyang
* @date 2022/5/23
*/
@Data
public class BookAddReqDto {
/**
* 作家ID
*/
private Long authorId;
/**
* 作家笔名
*/
private String penName;
/**
* 作品方向;0-男频 1-女频
*/
@Schema(description = "作品方向;0-男频 1-女频", required = true)
@NotNull
private Integer workDirection;
/**
* 类别ID
*/
@Schema(description = "类别ID", required = true)
@NotNull
private Long categoryId;
/**
* 类别名
*/
@Schema(description = "类别名", required = true)
@NotBlank
private String categoryName;
/**
* 小说封面地址
*/
@Schema(description = "小说封面地址", required = true)
@NotBlank
private String picUrl;
/**
* 小说名
*/
@Schema(description = "小说名", required = true)
@NotBlank
private String bookName;
/**
* 书籍描述
*/
@Schema(description = "书籍描述", required = true)
@NotBlank
private String bookDesc;
/**
* 是否收费;1-收费 0-免费
*/
@Schema(description = "是否收费;1-收费 0-免费", required = true)
@NotNull
private Integer isVip;
}

View File

@@ -0,0 +1,27 @@
package io.github.xxyopen.novel.book.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
/**
* 小说评论 请求DTO
* @author xiongxiaoyang
* @date 2022/5/17
*/
@Data
public class BookCommentReqDto {
private Long commentId;
private Long userId;
@Schema(description = "小说ID")
private Long bookId;
@Schema(description = "评论内容")
private String commentContent;
}

View File

@@ -0,0 +1,24 @@
package io.github.xxyopen.novel.book.dto.req;
import io.github.xxyopen.novel.common.req.PageReqDto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
/**
* 章节发布页 请求DTO
*
* @author xiongxiaoyang
* @date 2022/5/23
*/
@Data
public class BookPageReqDto extends PageReqDto {
/**
* 作家ID
*/
@Schema(description = "作家ID", required = true)
private Long authorId;
}

View File

@@ -0,0 +1,78 @@
package io.github.xxyopen.novel.book.dto.req;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.github.xxyopen.novel.common.req.PageReqDto;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
* 小说搜索 请求DTO
*
* @author xiongxiaoyang
* @date 2022/5/16
*/
@Data
public class BookSearchReqDto extends PageReqDto {
/**
* 搜索关键字
*/
@Parameter(description = "搜索关键字")
private String keyword;
/**
* 作品方向
*/
@Parameter(description = "作品方向")
private Integer workDirection;
/**
* 分类ID
*/
@Parameter(description = "分类ID")
private Integer categoryId;
/**
* 是否收费,1:收费,0:免费
*/
@Parameter(description = "是否收费,1:收费,0:免费")
private Integer isVip;
/**
* 小说更新状态,0:连载中,1:已完结
*/
@Parameter(description = "小说更新状态,0:连载中,1:已完结")
private Integer bookStatus;
/**
* 字数最小值
*/
@Parameter(description = "字数最小值")
private Integer wordCountMin;
/**
* 字数最大值
*/
@Parameter(description = "字数最大值")
private Integer wordCountMax;
/**
* 最小更新时间
* 如果使用Get请求,直接使用对象接收,则可以使用@DateTimeFormat注解进行格式化;
* 如果使用Post请求,@RequestBody接收请求体参数,默认解析日期格式为yyyy-MM-dd HH:mm:ss ,
* 如果需要接收其他格式的参数,则可以使用@JsonFormat注解
* */
@Parameter(description = "最小更新时间")
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd")
private Date updateTimeMin;
/**
* 排序字段
*/
@Parameter(description = "排序字段")
private String sort;
}

View File

@@ -0,0 +1,50 @@
package io.github.xxyopen.novel.book.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
/**
* 章节发布 请求DTO
*
* @author xiongxiaoyang
* @date 2022/5/23
*/
@Data
public class ChapterAddReqDto {
/**
* 小说ID
*/
private Long bookId;
/**
* 作家ID
*/
private Long authorId;
/**
* 章节名
*/
@NotBlank
@Schema(description = "章节名", required = true)
private String chapterName;
/**
* 章节内容
*/
@Schema(description = "章节内容", required = true)
@NotBlank
@Length(min = 50)
private String chapterContent;
/**
* 是否收费;1-收费 0-免费
*/
@Schema(description = "是否收费;1-收费 0-免费", required = true)
@NotNull
private Integer isVip;
}

View File

@@ -0,0 +1,25 @@
package io.github.xxyopen.novel.book.dto.req;
import io.github.xxyopen.novel.common.req.PageReqDto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
/**
* 章节发布页 请求DTO
*
* @author xiongxiaoyang
* @date 2022/5/23
*/
@Data
public class ChapterPageReqDto extends PageReqDto {
/**
* 小说ID
*/
@NotBlank
@Schema(description = "小说ID", required = true)
private Long bookId;
}

View File

@@ -0,0 +1,29 @@
package io.github.xxyopen.novel.book.dto.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
/**
* 小说分类 响应DTO
*
* @author xiongxiaoyang
* @date 2022/5/16
*/
@Data
@Builder
public class BookCategoryRespDto {
/**
* 类别ID
*/
@Schema(description = "类别ID")
private Long id;
/**
* 类别名
*/
@Schema(description = "类别名")
private String name;
}

View File

@@ -0,0 +1,31 @@
package io.github.xxyopen.novel.book.dto.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
/**
* 小说章节相关 响应DTO
*
* @author xiongxiaoyang
* @date 2022/5/15
*/
@Data
@Builder
public class BookChapterAboutRespDto {
private BookChapterRespDto chapterInfo;
/**
* 章节总数
*/
@Schema(description = "章节总数")
private Long chapterTotal;
/**
* 内容概要(30字)
*/
@Schema(description = " 内容概要(30字)")
private String contentSummary;
}

View File

@@ -0,0 +1,78 @@
package io.github.xxyopen.novel.book.dto.resp;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 小说章节 响应DTO
*
* @author xiongxiaoyang
* @date 2022/5/15
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class BookChapterRespDto implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 章节ID
*/
@Schema(description = "章节ID")
private Long id;
/**
* 小说ID
*/
@Schema(description = "小说ID")
private Long bookId;
/**
* 章节号
*/
@Schema(description = "章节号")
private Integer chapterNum;
/**
* 章节名
*/
@Schema(description = "章节名")
private String chapterName;
/**
* 章节字数
*/
@Schema(description = "章节字数")
private Integer chapterWordCount;
/**
* 章节更新时间
* <p>
* ⚠️这里的 @JsonFormat 注解必须在该类有无参构造函数的情况下才能生效
*
* @Builder 注解会自动帮该类生成全参构造函数,导致丢失了默认的无参构造函数。
* <p>
* 所以,必须显示为该类生成无参构造函数。如果没有显示为该类生成无参构造函数,会报 Json 反序列化的错误
*/
@Schema(description = "章节更新时间")
@JsonFormat(pattern = "yyyy/MM/dd HH:mm")
private LocalDateTime chapterUpdateTime;
/**
* 是否收费;1-收费 0-免费
*/
@Schema(description = "是否收费;1-收费 0-免费")
private Integer isVip;
}

View File

@@ -0,0 +1,54 @@
package io.github.xxyopen.novel.book.dto.resp;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.github.xxyopen.novel.common.json.serializer.UsernameSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
/**
* 小说评论 响应DTO
* @author xiongxiaoyang
* @date 2022/5/17
*/
@Data
@Builder
public class BookCommentRespDto {
@Schema(description = "评论总数")
private Long commentTotal;
@Schema(description = "评论列表")
private List<CommentInfo> comments;
@Data
@Builder
public static class CommentInfo {
@Schema(description = "评论ID")
private Long id;
@Schema(description = "评论内容")
private String commentContent;
@Schema(description = "评论用户")
@JsonSerialize(using = UsernameSerializer.class)
private String commentUser;
@Schema(description = "评论用户ID")
private Long commentUserId;
@Schema(description = "评论用户头像")
private String commentUserPhoto;
@Schema(description = "评论时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime commentTime;
}
}

View File

@@ -0,0 +1,35 @@
package io.github.xxyopen.novel.book.dto.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
/**
* 小说内容相关 响应DTO
*
* @author xiongxiaoyang
* @date 2022/5/15
*/
@Data
@Builder
public class BookContentAboutRespDto {
/**
* 小说信息
*/
@Schema(description = "小说信息")
private BookInfoRespDto bookInfo;
/**
* 章节信息
*/
@Schema(description = "章节信息")
private BookChapterRespDto chapterInfo;
/**
* 章节内容
*/
@Schema(description = "章节内容")
private String bookContent;
}

View File

@@ -0,0 +1,105 @@
package io.github.xxyopen.novel.book.dto.resp;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Elasticsearch 存储小说 DTO
* @author xiongxiaoyang
* @date 2022/5/23
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BookEsRespDto {
/**
* id
*/
private Long id;
/**
* 作品方向;0-男频 1-女频
*/
private Integer workDirection;
/**
* 类别ID
*/
private Long categoryId;
/**
* 类别名
*/
private String categoryName;
/**
* 小说名
*/
private String bookName;
/**
* 作家id
*/
private Long authorId;
/**
* 作家名
*/
private String authorName;
/**
* 书籍描述
*/
private String bookDesc;
/**
* 评分;总分:10 ,真实评分 = score/10
*/
private Integer score;
/**
* 书籍状态;0-连载中 1-已完结
*/
private Integer bookStatus;
/**
* 点击量
*/
private Long visitCount;
/**
* 总字数
*/
private Integer wordCount;
/**
* 评论数
*/
private Integer commentCount;
/**
* 最新章节ID
*/
private Long lastChapterId;
/**
* 最新章节名
*/
private String lastChapterName;
/**
* 最新章节更新时间
*/
private Long lastChapterUpdateTime;
/**
* 是否收费;1-收费 0-免费
*/
private Integer isVip;
}

View File

@@ -0,0 +1,122 @@
package io.github.xxyopen.novel.book.dto.resp;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 小说信息 响应DTO
*
* @author xiongxiaoyang
* @date 2022/5/15
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BookInfoRespDto {
/**
* ID
*/
@Schema(description = "小说ID")
private Long id;
/**
* 类别ID
*/
@Schema(description = "类别ID")
private Long categoryId;
/**
* 类别名
*/
@Schema(description = "类别名")
private String categoryName;
/**
* 小说封面地址
*/
@Schema(description = "小说封面地址")
private String picUrl;
/**
* 小说名
*/
@Schema(description = "小说名")
private String bookName;
/**
* 作家id
*/
@Schema(description = "作家id")
private Long authorId;
/**
* 作家名
*/
@Schema(description = "作家名")
private String authorName;
/**
* 书籍描述
*/
@Schema(description = "书籍描述")
private String bookDesc;
/**
* 书籍状态;0-连载中 1-已完结
*/
@Schema(description = "书籍状态;0-连载中 1-已完结")
private Integer bookStatus;
/**
* 点击量
*/
@Schema(description = "点击量")
private Long visitCount;
/**
* 总字数
*/
@Schema(description = "总字数")
private Integer wordCount;
/**
* 评论数
*/
@Schema(description = "评论数")
private Integer commentCount;
/**
* 首章节ID
*/
@Schema(description = "首章节ID")
private Long firstChapterId;
/**
* 最新章节ID
*/
@Schema(description = "最新章节ID")
private Long lastChapterId;
/**
* 最新章节名
*/
@Schema(description = "最新章节名")
private String lastChapterName;
/**
* 最新章节更新时间
*/
@Schema(description = "最新章节更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,84 @@
package io.github.xxyopen.novel.book.dto.resp;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 小说排行榜 响应DTO
*
* @author xiongxiaoyang
* @date 2022/5/14
*/
@Data
public class BookRankRespDto implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@Schema(description = "小说ID")
private Long id;
/**
* 类别ID
*/
@Schema(description = "类别ID")
private Long categoryId;
/**
* 类别名
*/
@Schema(description = "类别名")
private String categoryName;
/**
* 小说封面地址
*/
@Schema(description = "小说封面地址")
private String picUrl;
/**
* 小说名
*/
@Schema(description = "小说名")
private String bookName;
/**
* 作家名
*/
@Schema(description = "作家名")
private String authorName;
/**
* 书籍描述
*/
@Schema(description = "书籍描述")
private String bookDesc;
/**
* 总字数
*/
@Schema(description = "总字数")
private Integer wordCount;
/**
* 最新章节名
*/
@Schema(description = "最新章节名")
private String lastChapterName;
/**
* 最新章节更新时间
*/
@Schema(description = "最新章节更新时间")
@JsonFormat(pattern = "MM/dd HH:mm")
private LocalDateTime lastChapterUpdateTime;
}

View File

@@ -0,0 +1,132 @@
package io.github.xxyopen.novel.book.feign;
import io.github.xxyopen.novel.book.dto.req.*;
import io.github.xxyopen.novel.book.dto.resp.BookChapterRespDto;
import io.github.xxyopen.novel.book.dto.resp.BookEsRespDto;
import io.github.xxyopen.novel.book.dto.resp.BookInfoRespDto;
import io.github.xxyopen.novel.common.constant.ApiRouterConsts;
import io.github.xxyopen.novel.common.constant.ErrorCodeEnum;
import io.github.xxyopen.novel.common.resp.PageRespDto;
import io.github.xxyopen.novel.common.resp.RestResp;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.ArrayList;
import java.util.List;
/**
* 小说微服务调用客户端
*
* @author xiongxiaoyang
* @date 2023/3/29
*/
@Component
@FeignClient(value = "novel-book-service", fallback = BookFeign.BookFeignFallback.class)
public interface BookFeign {
/**
* 查询下一批保存到 ES 中的小说列表
*/
@PostMapping(ApiRouterConsts.API_INNER_BOOK_URL_PREFIX + "/listNextEsBooks")
RestResp<List<BookEsRespDto>> listNextEsBooks(Long maxBookId);
/**
* 批量查询小说信息
*/
@PostMapping(ApiRouterConsts.API_INNER_BOOK_URL_PREFIX + "/listBookInfoByIds")
RestResp<List<BookInfoRespDto>> listBookInfoByIds(List<Long> bookIds);
/**
* 发表评论
*/
@PostMapping(ApiRouterConsts.API_INNER_BOOK_URL_PREFIX + "/publishComment")
RestResp<Void> publishComment(BookCommentReqDto dto);
/**
* 修改评论
*/
@PostMapping(ApiRouterConsts.API_INNER_BOOK_URL_PREFIX + "/updateComment")
RestResp<Void> updateComment(BookCommentReqDto dto);
/**
* 删除评论接口
*/
@PostMapping(ApiRouterConsts.API_INNER_BOOK_URL_PREFIX + "/deleteComment")
RestResp<Void> deleteComment(@RequestBody BookCommentReqDto dto);
/**
* 小说发布接口
*/
@PostMapping(ApiRouterConsts.API_INNER_BOOK_URL_PREFIX + "/publishBook")
RestResp<Void> publishBook(BookAddReqDto dto);
/**
* 小说发布列表查询接口
*/
@PostMapping(ApiRouterConsts.API_INNER_BOOK_URL_PREFIX + "/listPublishBooks")
RestResp<PageRespDto<BookInfoRespDto>> listPublishBooks(BookPageReqDto dto);
/**
* 小说章节发布接口
*/
@PostMapping(ApiRouterConsts.API_INNER_BOOK_URL_PREFIX + "/publishBookChapter")
RestResp<Void> publishBookChapter(ChapterAddReqDto dto);
/**
* 小说章节发布列表查询接口
*/
@PostMapping(ApiRouterConsts.API_INNER_BOOK_URL_PREFIX + "/listPublishBookChapters")
RestResp<PageRespDto<BookChapterRespDto>> listPublishBookChapters(ChapterPageReqDto dto);
@Component
class BookFeignFallback implements BookFeign {
@Override
public RestResp<List<BookEsRespDto>> listNextEsBooks(Long maxBookId) {
return RestResp.ok(new ArrayList<>(0));
}
@Override
public RestResp<List<BookInfoRespDto>> listBookInfoByIds(List<Long> bookIds) {
return RestResp.ok(new ArrayList<>(0));
}
@Override
public RestResp<Void> publishComment(BookCommentReqDto dto) {
return RestResp.fail(ErrorCodeEnum.THIRD_SERVICE_ERROR);
}
@Override
public RestResp<Void> updateComment(BookCommentReqDto dto) {
return RestResp.fail(ErrorCodeEnum.THIRD_SERVICE_ERROR);
}
@Override
public RestResp<Void> deleteComment(BookCommentReqDto dto) {
return RestResp.fail(ErrorCodeEnum.THIRD_SERVICE_ERROR);
}
@Override
public RestResp<Void> publishBook(BookAddReqDto dto) {
return RestResp.fail(ErrorCodeEnum.THIRD_SERVICE_ERROR);
}
@Override
public RestResp<PageRespDto<BookInfoRespDto>> listPublishBooks(BookPageReqDto dto) {
return RestResp.ok(PageRespDto.of(dto.getPageNum(), dto.getPageSize(), 0, new ArrayList<>(0)));
}
@Override
public RestResp<Void> publishBookChapter(ChapterAddReqDto dto) {
return RestResp.fail(ErrorCodeEnum.THIRD_SERVICE_ERROR);
}
@Override
public RestResp<PageRespDto<BookChapterRespDto>> listPublishBookChapters(ChapterPageReqDto dto) {
return RestResp.ok(PageRespDto.of(dto.getPageNum(), dto.getPageSize(), 0, new ArrayList<>(0)));
}
}
}