mirror of
https://gitee.com/novel_dev_team/novel-cloud
synced 2026-07-20 17:55:01 +08:00
refactor: 基于 novel 项目 & Spring Cloud 2022 & Spring Cloud Alibaba 2022 重构
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
package io.github.xxyopen.novel.book;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
@SpringBootApplication(scanBasePackages = {"io.github.xxyopen.novel"})
|
||||
@MapperScan("io.github.xxyopen.novel.book.dao.mapper")
|
||||
@EnableCaching
|
||||
@EnableDiscoveryClient
|
||||
@EnableFeignClients(basePackages = {"io.github.xxyopen.novel.user.feign"})
|
||||
public class NovelBookApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(NovelBookApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package io.github.xxyopen.novel.book.config;
|
||||
|
||||
import io.github.xxyopen.novel.common.constant.ApiRouterConsts;
|
||||
import io.github.xxyopen.novel.config.interceptor.TokenParseInterceptor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* Spring Web Mvc 相关配置不要加 @EnableWebMvc 注解,否则会导致 jackson 的全局配置失效。因为 @EnableWebMvc 注解会导致 WebMvcAutoConfiguration 自动配置失效
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/5/18
|
||||
*/
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
private final TokenParseInterceptor tokenParseInterceptor;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
|
||||
// Token 解析拦截器
|
||||
registry.addInterceptor(tokenParseInterceptor)
|
||||
// 拦截小说内容查询接口,需要解析 token 以判断该用户是否有权阅读该章节(付费章节是否已购买)
|
||||
.addPathPatterns(ApiRouterConsts.API_FRONT_BOOK_URL_PREFIX + "/content/*");
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package io.github.xxyopen.novel.book.controller.front;
|
||||
|
||||
import io.github.xxyopen.novel.book.dto.resp.*;
|
||||
import io.github.xxyopen.novel.book.service.BookService;
|
||||
import io.github.xxyopen.novel.common.constant.ApiRouterConsts;
|
||||
import io.github.xxyopen.novel.common.resp.RestResp;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 前台门户-小说模块 API 控制器
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/5/14
|
||||
*/
|
||||
@Tag(name = "FrontBookController", description = "前台门户-小说模块")
|
||||
@RestController
|
||||
@RequestMapping(ApiRouterConsts.API_FRONT_BOOK_URL_PREFIX)
|
||||
@RequiredArgsConstructor
|
||||
public class FrontBookController {
|
||||
|
||||
private final BookService bookService;
|
||||
|
||||
/**
|
||||
* 小说分类列表查询接口
|
||||
*/
|
||||
@Operation(summary = "小说分类列表查询接口")
|
||||
@GetMapping("category/list")
|
||||
public RestResp<List<BookCategoryRespDto>> listCategory(
|
||||
@Parameter(description = "作品方向", required = true) Integer workDirection) {
|
||||
return bookService.listCategory(workDirection);
|
||||
}
|
||||
|
||||
/**
|
||||
* 小说信息查询接口
|
||||
*/
|
||||
@Operation(summary = "小说信息查询接口")
|
||||
@GetMapping("{id}")
|
||||
public RestResp<BookInfoRespDto> getBookById(
|
||||
@Parameter(description = "小说 ID") @PathVariable("id") Long bookId) {
|
||||
return bookService.getBookById(bookId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加小说点击量接口
|
||||
*/
|
||||
@Operation(summary = "增加小说点击量接口")
|
||||
@PostMapping("visit")
|
||||
public RestResp<Void> addVisitCount(@Parameter(description = "小说ID") Long bookId) {
|
||||
return bookService.addVisitCount(bookId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 小说最新章节相关信息查询接口
|
||||
*/
|
||||
@Operation(summary = "小说最新章节相关信息查询接口")
|
||||
@GetMapping("last_chapter/about")
|
||||
public RestResp<BookChapterAboutRespDto> getLastChapterAbout(
|
||||
@Parameter(description = "小说ID") Long bookId) {
|
||||
return bookService.getLastChapterAbout(bookId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 小说推荐列表查询接口
|
||||
*/
|
||||
@Operation(summary = "小说推荐列表查询接口")
|
||||
@GetMapping("rec_list")
|
||||
public RestResp<List<BookInfoRespDto>> listRecBooks(
|
||||
@Parameter(description = "小说ID") Long bookId) throws NoSuchAlgorithmException {
|
||||
return bookService.listRecBooks(bookId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 小说章节列表查询接口
|
||||
*/
|
||||
@Operation(summary = "小说章节列表查询接口")
|
||||
@GetMapping("chapter/list")
|
||||
public RestResp<List<BookChapterRespDto>> listChapters(
|
||||
@Parameter(description = "小说ID") Long bookId) {
|
||||
return bookService.listChapters(bookId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 小说内容相关信息查询接口
|
||||
*/
|
||||
@Operation(summary = "小说内容相关信息查询接口")
|
||||
@GetMapping("content/{chapterId}")
|
||||
public RestResp<BookContentAboutRespDto> getBookContentAbout(
|
||||
@Parameter(description = "章节ID") @PathVariable("chapterId") Long chapterId) {
|
||||
return bookService.getBookContentAbout(chapterId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上一章节ID接口
|
||||
*/
|
||||
@Operation(summary = "获取上一章节ID接口")
|
||||
@GetMapping("pre_chapter_id/{chapterId}")
|
||||
public RestResp<Long> getPreChapterId(
|
||||
@Parameter(description = "章节ID") @PathVariable("chapterId") Long chapterId) {
|
||||
return bookService.getPreChapterId(chapterId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下一章节ID接口
|
||||
*/
|
||||
@Operation(summary = "获取下一章节ID接口")
|
||||
@GetMapping("next_chapter_id/{chapterId}")
|
||||
public RestResp<Long> getNextChapterId(
|
||||
@Parameter(description = "章节ID") @PathVariable("chapterId") Long chapterId) {
|
||||
return bookService.getNextChapterId(chapterId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 小说点击榜查询接口
|
||||
*/
|
||||
@Operation(summary = "小说点击榜查询接口")
|
||||
@GetMapping("visit_rank")
|
||||
public RestResp<List<BookRankRespDto>> listVisitRankBooks() {
|
||||
return bookService.listVisitRankBooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* 小说新书榜查询接口
|
||||
*/
|
||||
@Operation(summary = "小说新书榜查询接口")
|
||||
@GetMapping("newest_rank")
|
||||
public RestResp<List<BookRankRespDto>> listNewestRankBooks() {
|
||||
return bookService.listNewestRankBooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* 小说更新榜查询接口
|
||||
*/
|
||||
@Operation(summary = "小说更新榜查询接口")
|
||||
@GetMapping("update_rank")
|
||||
public RestResp<List<BookRankRespDto>> listUpdateRankBooks() {
|
||||
return bookService.listUpdateRankBooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* 小说最新评论查询接口
|
||||
*/
|
||||
@Operation(summary = "小说最新评论查询接口")
|
||||
@GetMapping("comment/newest_list")
|
||||
public RestResp<BookCommentRespDto> listNewestComments(
|
||||
@Parameter(description = "小说ID") Long bookId) {
|
||||
return bookService.listNewestComments(bookId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package io.github.xxyopen.novel.book.controller.inner;
|
||||
|
||||
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.book.service.BookService;
|
||||
import io.github.xxyopen.novel.common.constant.ApiRouterConsts;
|
||||
import io.github.xxyopen.novel.common.resp.PageRespDto;
|
||||
import io.github.xxyopen.novel.common.resp.RestResp;
|
||||
import io.github.xxyopen.novel.user.dto.resp.UserInfoRespDto;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 小说微服务内部调用接口
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2023/3/29
|
||||
*/
|
||||
@Tag(name = "InnerBookController", description = "内部调用-小说模块")
|
||||
@RestController
|
||||
@RequestMapping(ApiRouterConsts.API_INNER_BOOK_URL_PREFIX)
|
||||
@RequiredArgsConstructor
|
||||
public class InnerBookController {
|
||||
|
||||
private final BookService bookService;
|
||||
|
||||
/**
|
||||
* 查询下一批保存到 ES 中的小说列表
|
||||
*/
|
||||
@Operation(summary = "查询下一批保存到 ES 中的小说列表")
|
||||
@PostMapping("listNextEsBooks")
|
||||
RestResp<List<BookEsRespDto>> listNextEsBooks(@Parameter(description = "已查询的最大小说ID") Long maxBookId) {
|
||||
return bookService.listNextEsBooks(maxBookId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量查询小说信息
|
||||
*/
|
||||
@Operation(summary = "批量查询小说信息")
|
||||
@PostMapping("listBookInfoByIds")
|
||||
RestResp<List<BookInfoRespDto>> listBookInfoByIds(@RequestBody List<Long> bookIds) {
|
||||
return bookService.listBookInfoByIds(bookIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发表评论接口
|
||||
*/
|
||||
@Operation(summary = "发表评论接口")
|
||||
@PostMapping("publishComment")
|
||||
public RestResp<Void> publishComment(@Valid @RequestBody BookCommentReqDto dto) {
|
||||
return bookService.saveComment(dto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改评论接口
|
||||
*/
|
||||
@Operation(summary = "修改评论接口")
|
||||
@PostMapping("updateComment")
|
||||
public RestResp<Void> updateComment(@Valid @RequestBody BookCommentReqDto dto) {
|
||||
return bookService.updateComment(dto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除评论接口
|
||||
*/
|
||||
@Operation(summary = "删除评论接口")
|
||||
@PostMapping("deleteComment")
|
||||
public RestResp<Void> deleteComment(@RequestBody BookCommentReqDto dto) {
|
||||
return bookService.deleteComment(dto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 小说发布接口
|
||||
*/
|
||||
@Operation(summary = "小说发布接口")
|
||||
@PostMapping("publishBook")
|
||||
public RestResp<Void> publishBook(@Valid @RequestBody BookAddReqDto dto) {
|
||||
return bookService.saveBook(dto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 小说发布列表查询接口
|
||||
*/
|
||||
@Operation(summary = "小说发布列表查询接口")
|
||||
@PostMapping("listPublishBooks")
|
||||
public RestResp<PageRespDto<BookInfoRespDto>> listPublishBooks(@RequestBody BookPageReqDto dto) {
|
||||
return bookService.listAuthorBooks(dto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 小说章节发布接口
|
||||
*/
|
||||
@Operation(summary = "小说章节发布接口")
|
||||
@PostMapping("publishBookChapter")
|
||||
public RestResp<Void> publishBookChapter(@Valid @RequestBody ChapterAddReqDto dto) {
|
||||
return bookService.saveBookChapter(dto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 小说章节发布列表查询接口
|
||||
*/
|
||||
@Operation(summary = "小说章节发布列表查询接口")
|
||||
@PostMapping("listPublishBookChapters")
|
||||
public RestResp<PageRespDto<BookChapterRespDto>> listPublishBookChapters(@RequestBody ChapterPageReqDto dto) {
|
||||
return bookService.listBookChapters(dto);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package io.github.xxyopen.novel.book.dao.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 小说类别
|
||||
* </p>
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/05/12
|
||||
*/
|
||||
@TableName("book_category")
|
||||
public class BookCategory implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 作品方向;0-男频 1-女频
|
||||
*/
|
||||
private Integer workDirection;
|
||||
|
||||
/**
|
||||
* 类别名
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private Integer sort;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getWorkDirection() {
|
||||
return workDirection;
|
||||
}
|
||||
|
||||
public void setWorkDirection(Integer workDirection) {
|
||||
this.workDirection = workDirection;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getSort() {
|
||||
return sort;
|
||||
}
|
||||
|
||||
public void setSort(Integer sort) {
|
||||
this.sort = sort;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(LocalDateTime updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BookCategory{" +
|
||||
"id=" + id +
|
||||
", workDirection=" + workDirection +
|
||||
", name=" + name +
|
||||
", sort=" + sort +
|
||||
", createTime=" + createTime +
|
||||
", updateTime=" + updateTime +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package io.github.xxyopen.novel.book.dao.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 小说章节
|
||||
* </p>
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/05/11
|
||||
*/
|
||||
@TableName("book_chapter")
|
||||
public class BookChapter implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 小说ID
|
||||
*/
|
||||
private Long bookId;
|
||||
|
||||
/**
|
||||
* 章节号
|
||||
*/
|
||||
private Integer chapterNum;
|
||||
|
||||
/**
|
||||
* 章节名
|
||||
*/
|
||||
private String chapterName;
|
||||
|
||||
/**
|
||||
* 章节字数
|
||||
*/
|
||||
private Integer wordCount;
|
||||
|
||||
/**
|
||||
* 是否收费;1-收费 0-免费
|
||||
*/
|
||||
private Integer isVip;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getBookId() {
|
||||
return bookId;
|
||||
}
|
||||
|
||||
public void setBookId(Long bookId) {
|
||||
this.bookId = bookId;
|
||||
}
|
||||
|
||||
public Integer getChapterNum() {
|
||||
return chapterNum;
|
||||
}
|
||||
|
||||
public void setChapterNum(Integer chapterNum) {
|
||||
this.chapterNum = chapterNum;
|
||||
}
|
||||
|
||||
public String getChapterName() {
|
||||
return chapterName;
|
||||
}
|
||||
|
||||
public void setChapterName(String chapterName) {
|
||||
this.chapterName = chapterName;
|
||||
}
|
||||
|
||||
public Integer getWordCount() {
|
||||
return wordCount;
|
||||
}
|
||||
|
||||
public void setWordCount(Integer wordCount) {
|
||||
this.wordCount = wordCount;
|
||||
}
|
||||
|
||||
public Integer getIsVip() {
|
||||
return isVip;
|
||||
}
|
||||
|
||||
public void setIsVip(Integer isVip) {
|
||||
this.isVip = isVip;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(LocalDateTime updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BookChapter{" +
|
||||
"id=" + id +
|
||||
", bookId=" + bookId +
|
||||
", chapterNum=" + chapterNum +
|
||||
", chapterName=" + chapterName +
|
||||
", wordCount=" + wordCount +
|
||||
", isVip=" + isVip +
|
||||
", createTime=" + createTime +
|
||||
", updateTime=" + updateTime +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package io.github.xxyopen.novel.book.dao.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 小说评论
|
||||
* </p>
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/05/11
|
||||
*/
|
||||
@TableName("book_comment")
|
||||
public class BookComment implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 评论小说ID
|
||||
*/
|
||||
private Long bookId;
|
||||
|
||||
/**
|
||||
* 评论用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 评价内容
|
||||
*/
|
||||
private String commentContent;
|
||||
|
||||
/**
|
||||
* 回复数量
|
||||
*/
|
||||
private Integer replyCount;
|
||||
|
||||
/**
|
||||
* 审核状态;0-待审核 1-审核通过 2-审核不通过
|
||||
*/
|
||||
private Integer auditStatus;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getBookId() {
|
||||
return bookId;
|
||||
}
|
||||
|
||||
public void setBookId(Long bookId) {
|
||||
this.bookId = bookId;
|
||||
}
|
||||
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(Long userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getCommentContent() {
|
||||
return commentContent;
|
||||
}
|
||||
|
||||
public void setCommentContent(String commentContent) {
|
||||
this.commentContent = commentContent;
|
||||
}
|
||||
|
||||
public Integer getReplyCount() {
|
||||
return replyCount;
|
||||
}
|
||||
|
||||
public void setReplyCount(Integer replyCount) {
|
||||
this.replyCount = replyCount;
|
||||
}
|
||||
|
||||
public Integer getAuditStatus() {
|
||||
return auditStatus;
|
||||
}
|
||||
|
||||
public void setAuditStatus(Integer auditStatus) {
|
||||
this.auditStatus = auditStatus;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(LocalDateTime updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BookComment{" +
|
||||
"id=" + id +
|
||||
", bookId=" + bookId +
|
||||
", userId=" + userId +
|
||||
", commentContent=" + commentContent +
|
||||
", replyCount=" + replyCount +
|
||||
", auditStatus=" + auditStatus +
|
||||
", createTime=" + createTime +
|
||||
", updateTime=" + updateTime +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package io.github.xxyopen.novel.book.dao.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 小说评论
|
||||
* </p>
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/05/11
|
||||
*/
|
||||
@TableName("book_comment_copy1")
|
||||
public class BookCommentCopy1 implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 评论小说ID
|
||||
*/
|
||||
private Long bookId;
|
||||
|
||||
/**
|
||||
* 评论用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 评价内容
|
||||
*/
|
||||
private String commentContent;
|
||||
|
||||
/**
|
||||
* 回复数量
|
||||
*/
|
||||
private Integer replyCount;
|
||||
|
||||
/**
|
||||
* 审核状态;0-待审核 1-审核通过 2-审核不通过
|
||||
*/
|
||||
private Integer auditStatus;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getBookId() {
|
||||
return bookId;
|
||||
}
|
||||
|
||||
public void setBookId(Long bookId) {
|
||||
this.bookId = bookId;
|
||||
}
|
||||
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(Long userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getCommentContent() {
|
||||
return commentContent;
|
||||
}
|
||||
|
||||
public void setCommentContent(String commentContent) {
|
||||
this.commentContent = commentContent;
|
||||
}
|
||||
|
||||
public Integer getReplyCount() {
|
||||
return replyCount;
|
||||
}
|
||||
|
||||
public void setReplyCount(Integer replyCount) {
|
||||
this.replyCount = replyCount;
|
||||
}
|
||||
|
||||
public Integer getAuditStatus() {
|
||||
return auditStatus;
|
||||
}
|
||||
|
||||
public void setAuditStatus(Integer auditStatus) {
|
||||
this.auditStatus = auditStatus;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(LocalDateTime updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BookCommentCopy1{" +
|
||||
"id=" + id +
|
||||
", bookId=" + bookId +
|
||||
", userId=" + userId +
|
||||
", commentContent=" + commentContent +
|
||||
", replyCount=" + replyCount +
|
||||
", auditStatus=" + auditStatus +
|
||||
", createTime=" + createTime +
|
||||
", updateTime=" + updateTime +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package io.github.xxyopen.novel.book.dao.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 小说评论回复
|
||||
* </p>
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/05/11
|
||||
*/
|
||||
@TableName("book_comment_reply")
|
||||
public class BookCommentReply implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 评论ID
|
||||
*/
|
||||
private Long commentId;
|
||||
|
||||
/**
|
||||
* 回复用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 回复内容
|
||||
*/
|
||||
private String replyContent;
|
||||
|
||||
/**
|
||||
* 审核状态;0-待审核 1-审核通过 2-审核不通过
|
||||
*/
|
||||
private Integer auditStatus;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getCommentId() {
|
||||
return commentId;
|
||||
}
|
||||
|
||||
public void setCommentId(Long commentId) {
|
||||
this.commentId = commentId;
|
||||
}
|
||||
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(Long userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getReplyContent() {
|
||||
return replyContent;
|
||||
}
|
||||
|
||||
public void setReplyContent(String replyContent) {
|
||||
this.replyContent = replyContent;
|
||||
}
|
||||
|
||||
public Integer getAuditStatus() {
|
||||
return auditStatus;
|
||||
}
|
||||
|
||||
public void setAuditStatus(Integer auditStatus) {
|
||||
this.auditStatus = auditStatus;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(LocalDateTime updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BookCommentReply{" +
|
||||
"id=" + id +
|
||||
", commentId=" + commentId +
|
||||
", userId=" + userId +
|
||||
", replyContent=" + replyContent +
|
||||
", auditStatus=" + auditStatus +
|
||||
", createTime=" + createTime +
|
||||
", updateTime=" + updateTime +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package io.github.xxyopen.novel.book.dao.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 小说内容
|
||||
* </p>
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/05/11
|
||||
*/
|
||||
@TableName("book_content")
|
||||
public class BookContent implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 章节ID
|
||||
*/
|
||||
private Long chapterId;
|
||||
|
||||
/**
|
||||
* 小说章节内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getChapterId() {
|
||||
return chapterId;
|
||||
}
|
||||
|
||||
public void setChapterId(Long chapterId) {
|
||||
this.chapterId = chapterId;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(LocalDateTime updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BookContent{" +
|
||||
"id=" + id +
|
||||
", chapterId=" + chapterId +
|
||||
", content=" + content +
|
||||
", createTime=" + createTime +
|
||||
", updateTime=" + updateTime +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
package io.github.xxyopen.novel.book.dao.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 小说信息
|
||||
* </p>
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/05/11
|
||||
*/
|
||||
@TableName("book_info")
|
||||
public class BookInfo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 作品方向;0-男频 1-女频
|
||||
*/
|
||||
private Integer workDirection;
|
||||
|
||||
/**
|
||||
* 类别ID
|
||||
*/
|
||||
private Long categoryId;
|
||||
|
||||
/**
|
||||
* 类别名
|
||||
*/
|
||||
private String categoryName;
|
||||
|
||||
/**
|
||||
* 小说封面地址
|
||||
*/
|
||||
private String picUrl;
|
||||
|
||||
/**
|
||||
* 小说名
|
||||
*/
|
||||
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 LocalDateTime lastChapterUpdateTime;
|
||||
|
||||
/**
|
||||
* 是否收费;1-收费 0-免费
|
||||
*/
|
||||
private Integer isVip;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getWorkDirection() {
|
||||
return workDirection;
|
||||
}
|
||||
|
||||
public void setWorkDirection(Integer workDirection) {
|
||||
this.workDirection = workDirection;
|
||||
}
|
||||
|
||||
public Long getCategoryId() {
|
||||
return categoryId;
|
||||
}
|
||||
|
||||
public void setCategoryId(Long categoryId) {
|
||||
this.categoryId = categoryId;
|
||||
}
|
||||
|
||||
public String getCategoryName() {
|
||||
return categoryName;
|
||||
}
|
||||
|
||||
public void setCategoryName(String categoryName) {
|
||||
this.categoryName = categoryName;
|
||||
}
|
||||
|
||||
public String getPicUrl() {
|
||||
return picUrl;
|
||||
}
|
||||
|
||||
public void setPicUrl(String picUrl) {
|
||||
this.picUrl = picUrl;
|
||||
}
|
||||
|
||||
public String getBookName() {
|
||||
return bookName;
|
||||
}
|
||||
|
||||
public void setBookName(String bookName) {
|
||||
this.bookName = bookName;
|
||||
}
|
||||
|
||||
public Long getAuthorId() {
|
||||
return authorId;
|
||||
}
|
||||
|
||||
public void setAuthorId(Long authorId) {
|
||||
this.authorId = authorId;
|
||||
}
|
||||
|
||||
public String getAuthorName() {
|
||||
return authorName;
|
||||
}
|
||||
|
||||
public void setAuthorName(String authorName) {
|
||||
this.authorName = authorName;
|
||||
}
|
||||
|
||||
public String getBookDesc() {
|
||||
return bookDesc;
|
||||
}
|
||||
|
||||
public void setBookDesc(String bookDesc) {
|
||||
this.bookDesc = bookDesc;
|
||||
}
|
||||
|
||||
public Integer getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
public void setScore(Integer score) {
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
public Integer getBookStatus() {
|
||||
return bookStatus;
|
||||
}
|
||||
|
||||
public void setBookStatus(Integer bookStatus) {
|
||||
this.bookStatus = bookStatus;
|
||||
}
|
||||
|
||||
public Long getVisitCount() {
|
||||
return visitCount;
|
||||
}
|
||||
|
||||
public void setVisitCount(Long visitCount) {
|
||||
this.visitCount = visitCount;
|
||||
}
|
||||
|
||||
public Integer getWordCount() {
|
||||
return wordCount;
|
||||
}
|
||||
|
||||
public void setWordCount(Integer wordCount) {
|
||||
this.wordCount = wordCount;
|
||||
}
|
||||
|
||||
public Integer getCommentCount() {
|
||||
return commentCount;
|
||||
}
|
||||
|
||||
public void setCommentCount(Integer commentCount) {
|
||||
this.commentCount = commentCount;
|
||||
}
|
||||
|
||||
public Long getLastChapterId() {
|
||||
return lastChapterId;
|
||||
}
|
||||
|
||||
public void setLastChapterId(Long lastChapterId) {
|
||||
this.lastChapterId = lastChapterId;
|
||||
}
|
||||
|
||||
public String getLastChapterName() {
|
||||
return lastChapterName;
|
||||
}
|
||||
|
||||
public void setLastChapterName(String lastChapterName) {
|
||||
this.lastChapterName = lastChapterName;
|
||||
}
|
||||
|
||||
public LocalDateTime getLastChapterUpdateTime() {
|
||||
return lastChapterUpdateTime;
|
||||
}
|
||||
|
||||
public void setLastChapterUpdateTime(LocalDateTime lastChapterUpdateTime) {
|
||||
this.lastChapterUpdateTime = lastChapterUpdateTime;
|
||||
}
|
||||
|
||||
public Integer getIsVip() {
|
||||
return isVip;
|
||||
}
|
||||
|
||||
public void setIsVip(Integer isVip) {
|
||||
this.isVip = isVip;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(LocalDateTime updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BookInfo{" +
|
||||
"id=" + id +
|
||||
", workDirection=" + workDirection +
|
||||
", categoryId=" + categoryId +
|
||||
", categoryName=" + categoryName +
|
||||
", picUrl=" + picUrl +
|
||||
", bookName=" + bookName +
|
||||
", authorId=" + authorId +
|
||||
", authorName=" + authorName +
|
||||
", bookDesc=" + bookDesc +
|
||||
", score=" + score +
|
||||
", bookStatus=" + bookStatus +
|
||||
", visitCount=" + visitCount +
|
||||
", wordCount=" + wordCount +
|
||||
", commentCount=" + commentCount +
|
||||
", lastChapterId=" + lastChapterId +
|
||||
", lastChapterName=" + lastChapterName +
|
||||
", lastChapterUpdateTime=" + lastChapterUpdateTime +
|
||||
", isVip=" + isVip +
|
||||
", createTime=" + createTime +
|
||||
", updateTime=" + updateTime +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package io.github.xxyopen.novel.book.dao.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookCategory;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 小说类别 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/05/12
|
||||
*/
|
||||
public interface BookCategoryMapper extends BaseMapper<BookCategory> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package io.github.xxyopen.novel.book.dao.mapper;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookChapter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 小说章节 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/05/11
|
||||
*/
|
||||
public interface BookChapterMapper extends BaseMapper<BookChapter> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package io.github.xxyopen.novel.book.dao.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookCommentCopy1;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 小说评论 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/05/11
|
||||
*/
|
||||
public interface BookCommentCopy1Mapper extends BaseMapper<BookCommentCopy1> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package io.github.xxyopen.novel.book.dao.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookComment;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 小说评论 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/05/11
|
||||
*/
|
||||
public interface BookCommentMapper extends BaseMapper<BookComment> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package io.github.xxyopen.novel.book.dao.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookCommentReply;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 小说评论回复 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/05/11
|
||||
*/
|
||||
public interface BookCommentReplyMapper extends BaseMapper<BookCommentReply> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package io.github.xxyopen.novel.book.dao.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookContent;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 小说内容 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/05/11
|
||||
*/
|
||||
public interface BookContentMapper extends BaseMapper<BookContent> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package io.github.xxyopen.novel.book.dao.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookInfo;
|
||||
import io.github.xxyopen.novel.book.dto.req.BookSearchReqDto;
|
||||
import io.github.xxyopen.novel.book.dto.resp.BookInfoRespDto;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 小说信息 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/05/11
|
||||
*/
|
||||
public interface BookInfoMapper extends BaseMapper<BookInfo> {
|
||||
|
||||
/**
|
||||
* 增加小说点击量
|
||||
*
|
||||
* @param bookId 小说ID
|
||||
*/
|
||||
void addVisitCount(@Param("bookId") Long bookId);
|
||||
|
||||
/**
|
||||
* 小说搜索
|
||||
* @param page mybatis-plus 分页对象
|
||||
* @param condition 搜索条件
|
||||
* @return 返回结果
|
||||
* */
|
||||
List<BookInfo> searchBooks(IPage<BookInfoRespDto> page, BookSearchReqDto condition);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package io.github.xxyopen.novel.book.manager.cache;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookCategory;
|
||||
import io.github.xxyopen.novel.book.dao.mapper.BookCategoryMapper;
|
||||
import io.github.xxyopen.novel.book.dto.resp.BookCategoryRespDto;
|
||||
import io.github.xxyopen.novel.common.constant.CacheConsts;
|
||||
import io.github.xxyopen.novel.common.constant.DatabaseConsts;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 小说分类 缓存管理类
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/5/12
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class BookCategoryCacheManager {
|
||||
|
||||
private final BookCategoryMapper bookCategoryMapper;
|
||||
|
||||
/**
|
||||
* 根据作品方向查询小说分类列表,并放入缓存中
|
||||
*/
|
||||
@Cacheable(cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER,
|
||||
value = CacheConsts.BOOK_CATEGORY_LIST_CACHE_NAME)
|
||||
public List<BookCategoryRespDto> listCategory(Integer workDirection) {
|
||||
QueryWrapper<BookCategory> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq(DatabaseConsts.BookCategoryTable.COLUMN_WORK_DIRECTION, workDirection);
|
||||
return bookCategoryMapper.selectList(queryWrapper).stream().map(v ->
|
||||
BookCategoryRespDto.builder()
|
||||
.id(v.getId())
|
||||
.name(v.getName())
|
||||
.build()).toList();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package io.github.xxyopen.novel.book.manager.cache;
|
||||
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookChapter;
|
||||
import io.github.xxyopen.novel.book.dao.mapper.BookChapterMapper;
|
||||
import io.github.xxyopen.novel.book.dto.resp.BookChapterRespDto;
|
||||
import io.github.xxyopen.novel.common.constant.CacheConsts;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 小说章节 缓存管理类
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/5/12
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class BookChapterCacheManager {
|
||||
|
||||
private final BookChapterMapper bookChapterMapper;
|
||||
|
||||
/**
|
||||
* 查询小说章节信息,并放入缓存中
|
||||
*/
|
||||
@Cacheable(cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER,
|
||||
value = CacheConsts.BOOK_CHAPTER_CACHE_NAME)
|
||||
public BookChapterRespDto getChapter(Long chapterId) {
|
||||
BookChapter bookChapter = bookChapterMapper.selectById(chapterId);
|
||||
return BookChapterRespDto.builder()
|
||||
.id(chapterId)
|
||||
.bookId(bookChapter.getBookId())
|
||||
.chapterNum(bookChapter.getChapterNum())
|
||||
.chapterName(bookChapter.getChapterName())
|
||||
.chapterWordCount(bookChapter.getWordCount())
|
||||
.chapterUpdateTime(bookChapter.getUpdateTime())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package io.github.xxyopen.novel.book.manager.cache;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookContent;
|
||||
import io.github.xxyopen.novel.book.dao.mapper.BookContentMapper;
|
||||
import io.github.xxyopen.novel.common.constant.CacheConsts;
|
||||
import io.github.xxyopen.novel.common.constant.DatabaseConsts;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 小说内容 缓存管理类
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/5/12
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class BookContentCacheManager {
|
||||
|
||||
private final BookContentMapper bookContentMapper;
|
||||
|
||||
/**
|
||||
* 查询小说内容,并放入缓存中
|
||||
*/
|
||||
@Cacheable(cacheManager = CacheConsts.REDIS_CACHE_MANAGER,
|
||||
value = CacheConsts.BOOK_CONTENT_CACHE_NAME)
|
||||
public String getBookContent(Long chapterId) {
|
||||
QueryWrapper<BookContent> contentQueryWrapper = new QueryWrapper<>();
|
||||
contentQueryWrapper.eq(DatabaseConsts.BookContentTable.COLUMN_CHAPTER_ID, chapterId)
|
||||
.last(DatabaseConsts.SqlEnum.LIMIT_1.getSql());
|
||||
BookContent bookContent = bookContentMapper.selectOne(contentQueryWrapper);
|
||||
return bookContent.getContent();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package io.github.xxyopen.novel.book.manager.cache;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookChapter;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookInfo;
|
||||
import io.github.xxyopen.novel.book.dao.mapper.BookChapterMapper;
|
||||
import io.github.xxyopen.novel.book.dao.mapper.BookInfoMapper;
|
||||
import io.github.xxyopen.novel.book.dto.resp.BookInfoRespDto;
|
||||
import io.github.xxyopen.novel.common.constant.CacheConsts;
|
||||
import io.github.xxyopen.novel.common.constant.DatabaseConsts;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.CachePut;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 小说信息 缓存管理类
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/5/12
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class BookInfoCacheManager {
|
||||
|
||||
private final BookInfoMapper bookInfoMapper;
|
||||
|
||||
private final BookChapterMapper bookChapterMapper;
|
||||
|
||||
/**
|
||||
* 从缓存中查询小说信息(先判断缓存中是否已存在,存在则直接从缓存中取,否则执行方法体中的逻辑后缓存结果)
|
||||
*/
|
||||
@Cacheable(cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER,
|
||||
value = CacheConsts.BOOK_INFO_CACHE_NAME)
|
||||
public BookInfoRespDto getBookInfo(Long id) {
|
||||
return cachePutBookInfo(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存小说信息(不管缓存中是否存在都执行方法体中的逻辑,然后缓存起来)
|
||||
*/
|
||||
@CachePut(cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER,
|
||||
value = CacheConsts.BOOK_INFO_CACHE_NAME)
|
||||
public BookInfoRespDto cachePutBookInfo(Long id) {
|
||||
// 查询基础信息
|
||||
BookInfo bookInfo = bookInfoMapper.selectById(id);
|
||||
// 查询首章ID
|
||||
QueryWrapper<BookChapter> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper
|
||||
.eq(DatabaseConsts.BookChapterTable.COLUMN_BOOK_ID, id)
|
||||
.orderByAsc(DatabaseConsts.BookChapterTable.COLUMN_CHAPTER_NUM)
|
||||
.last(DatabaseConsts.SqlEnum.LIMIT_1.getSql());
|
||||
BookChapter firstBookChapter = bookChapterMapper.selectOne(queryWrapper);
|
||||
// 组装响应对象
|
||||
return BookInfoRespDto.builder()
|
||||
.id(bookInfo.getId())
|
||||
.bookName(bookInfo.getBookName())
|
||||
.bookDesc(bookInfo.getBookDesc())
|
||||
.bookStatus(bookInfo.getBookStatus())
|
||||
.authorId(bookInfo.getAuthorId())
|
||||
.authorName(bookInfo.getAuthorName())
|
||||
.categoryId(bookInfo.getCategoryId())
|
||||
.categoryName(bookInfo.getCategoryName())
|
||||
.commentCount(bookInfo.getCommentCount())
|
||||
.firstChapterId(firstBookChapter.getId())
|
||||
.lastChapterId(bookInfo.getLastChapterId())
|
||||
.picUrl(bookInfo.getPicUrl())
|
||||
.visitCount(bookInfo.getVisitCount())
|
||||
.wordCount(bookInfo.getWordCount())
|
||||
.build();
|
||||
}
|
||||
|
||||
@CacheEvict(cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER,
|
||||
value = CacheConsts.BOOK_INFO_CACHE_NAME)
|
||||
public void evictBookInfoCache(Long ignoredId) {
|
||||
// 调用此方法自动清除小说信息的缓存
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询每个类别下最新更新的 500 个小说ID列表,并放入缓存中 1 个小时
|
||||
*/
|
||||
@Cacheable(cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER,
|
||||
value = CacheConsts.LAST_UPDATE_BOOK_ID_LIST_CACHE_NAME)
|
||||
public List<Long> getLastUpdateIdList(Long categoryId) {
|
||||
QueryWrapper<BookInfo> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq(DatabaseConsts.BookTable.COLUMN_CATEGORY_ID, categoryId)
|
||||
.gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT, 0)
|
||||
.orderByDesc(DatabaseConsts.BookTable.COLUMN_LAST_CHAPTER_UPDATE_TIME)
|
||||
.last(DatabaseConsts.SqlEnum.LIMIT_500.getSql());
|
||||
return bookInfoMapper.selectList(queryWrapper).stream().map(BookInfo::getId).toList();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package io.github.xxyopen.novel.book.manager.cache;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookInfo;
|
||||
import io.github.xxyopen.novel.book.dao.mapper.BookInfoMapper;
|
||||
import io.github.xxyopen.novel.book.dto.resp.BookRankRespDto;
|
||||
import io.github.xxyopen.novel.common.constant.CacheConsts;
|
||||
import io.github.xxyopen.novel.common.constant.DatabaseConsts;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 小说排行榜 缓存管理类
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/5/12
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class BookRankCacheManager {
|
||||
|
||||
private final BookInfoMapper bookInfoMapper;
|
||||
|
||||
/**
|
||||
* 查询小说点击榜列表,并放入缓存中
|
||||
*/
|
||||
@Cacheable(cacheManager = CacheConsts.REDIS_CACHE_MANAGER,
|
||||
value = CacheConsts.BOOK_VISIT_RANK_CACHE_NAME)
|
||||
public List<BookRankRespDto> listVisitRankBooks() {
|
||||
QueryWrapper<BookInfo> bookInfoQueryWrapper = new QueryWrapper<>();
|
||||
bookInfoQueryWrapper.orderByDesc(DatabaseConsts.BookTable.COLUMN_VISIT_COUNT);
|
||||
return listRankBooks(bookInfoQueryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询小说新书榜列表,并放入缓存中
|
||||
*/
|
||||
@Cacheable(cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER,
|
||||
value = CacheConsts.BOOK_NEWEST_RANK_CACHE_NAME)
|
||||
public List<BookRankRespDto> listNewestRankBooks() {
|
||||
QueryWrapper<BookInfo> bookInfoQueryWrapper = new QueryWrapper<>();
|
||||
bookInfoQueryWrapper
|
||||
.gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT, 0)
|
||||
.orderByDesc(DatabaseConsts.CommonColumnEnum.CREATE_TIME.getName());
|
||||
return listRankBooks(bookInfoQueryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询小说更新榜列表,并放入缓存中
|
||||
*/
|
||||
@Cacheable(cacheManager = CacheConsts.CAFFEINE_CACHE_MANAGER,
|
||||
value = CacheConsts.BOOK_UPDATE_RANK_CACHE_NAME)
|
||||
public List<BookRankRespDto> listUpdateRankBooks() {
|
||||
QueryWrapper<BookInfo> bookInfoQueryWrapper = new QueryWrapper<>();
|
||||
bookInfoQueryWrapper
|
||||
.gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT, 0)
|
||||
.orderByDesc(DatabaseConsts.CommonColumnEnum.UPDATE_TIME.getName());
|
||||
return listRankBooks(bookInfoQueryWrapper);
|
||||
}
|
||||
|
||||
private List<BookRankRespDto> listRankBooks(QueryWrapper<BookInfo> bookInfoQueryWrapper) {
|
||||
bookInfoQueryWrapper
|
||||
.gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT, 0)
|
||||
.last(DatabaseConsts.SqlEnum.LIMIT_30.getSql());
|
||||
return bookInfoMapper.selectList(bookInfoQueryWrapper).stream().map(v -> {
|
||||
BookRankRespDto respDto = new BookRankRespDto();
|
||||
respDto.setId(v.getId());
|
||||
respDto.setCategoryId(v.getCategoryId());
|
||||
respDto.setCategoryName(v.getCategoryName());
|
||||
respDto.setBookName(v.getBookName());
|
||||
respDto.setAuthorName(v.getAuthorName());
|
||||
respDto.setPicUrl(v.getPicUrl());
|
||||
respDto.setBookDesc(v.getBookDesc());
|
||||
respDto.setLastChapterName(v.getLastChapterName());
|
||||
respDto.setLastChapterUpdateTime(v.getLastChapterUpdateTime());
|
||||
respDto.setWordCount(v.getWordCount());
|
||||
return respDto;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package io.github.xxyopen.novel.book.manager.feign;
|
||||
|
||||
import io.github.xxyopen.novel.common.constant.ErrorCodeEnum;
|
||||
import io.github.xxyopen.novel.common.resp.RestResp;
|
||||
import io.github.xxyopen.novel.user.dto.resp.UserInfoRespDto;
|
||||
import io.github.xxyopen.novel.user.feign.UserFeign;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 用户微服务调用 Feign 客户端管理
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2023/3/29
|
||||
*/
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class UserFeignManager {
|
||||
|
||||
private final UserFeign userFeign;
|
||||
|
||||
public List<UserInfoRespDto> listUserInfoByIds(List<Long> userIds) {
|
||||
|
||||
RestResp<List<UserInfoRespDto>> resp = userFeign.listUserInfoByIds(userIds);
|
||||
if (Objects.equals(ErrorCodeEnum.OK.getCode(), resp.getCode())) {
|
||||
return resp.getData();
|
||||
}
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package io.github.xxyopen.novel.book.manager.mq;
|
||||
|
||||
import io.github.xxyopen.novel.common.constant.AmqpConsts;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.amqp.core.AmqpTemplate;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
/**
|
||||
* AMQP 消息管理类
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/5/25
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AmqpMsgManager {
|
||||
|
||||
private final AmqpTemplate amqpTemplate;
|
||||
|
||||
@Value("${spring.amqp.enabled:false}")
|
||||
private boolean amqpEnabled;
|
||||
|
||||
/**
|
||||
* 发送小说信息改变消息
|
||||
*/
|
||||
public void sendBookChangeMsg(Long bookId) {
|
||||
if (amqpEnabled) {
|
||||
sendAmqpMessage(amqpTemplate, AmqpConsts.BookChangeMq.EXCHANGE_NAME, null, bookId);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendAmqpMessage(AmqpTemplate amqpTemplate, String exchange, String routingKey,
|
||||
Object message) {
|
||||
// 如果在事务中则在事务执行完成后再发送,否则可以直接发送
|
||||
if (TransactionSynchronizationManager.isActualTransactionActive()) {
|
||||
TransactionSynchronizationManager.registerSynchronization(
|
||||
new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
amqpTemplate.convertAndSend(exchange, routingKey, message);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
amqpTemplate.convertAndSend(exchange, routingKey, message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package io.github.xxyopen.novel.book.service;
|
||||
|
||||
|
||||
import io.github.xxyopen.novel.book.dto.req.*;
|
||||
import io.github.xxyopen.novel.book.dto.resp.*;
|
||||
import io.github.xxyopen.novel.common.resp.PageRespDto;
|
||||
import io.github.xxyopen.novel.common.resp.RestResp;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 小说模块 服务类
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/5/14
|
||||
*/
|
||||
public interface BookService {
|
||||
|
||||
/**
|
||||
* 小说点击榜查询
|
||||
*
|
||||
* @return 小说点击排行列表
|
||||
*/
|
||||
RestResp<List<BookRankRespDto>> listVisitRankBooks();
|
||||
|
||||
/**
|
||||
* 小说新书榜查询
|
||||
*
|
||||
* @return 小说新书排行列表
|
||||
*/
|
||||
RestResp<List<BookRankRespDto>> listNewestRankBooks();
|
||||
|
||||
/**
|
||||
* 小说更新榜查询
|
||||
*
|
||||
* @return 小说更新排行列表
|
||||
*/
|
||||
RestResp<List<BookRankRespDto>> listUpdateRankBooks();
|
||||
|
||||
/**
|
||||
* 小说信息查询
|
||||
*
|
||||
* @param bookId 小说ID
|
||||
* @return 小说信息
|
||||
*/
|
||||
RestResp<BookInfoRespDto> getBookById(Long bookId);
|
||||
|
||||
/**
|
||||
* 小说内容相关信息查询
|
||||
*
|
||||
* @param chapterId 章节ID
|
||||
* @return 内容相关联的信息
|
||||
*/
|
||||
RestResp<BookContentAboutRespDto> getBookContentAbout(Long chapterId);
|
||||
|
||||
/**
|
||||
* 小说最新章节相关信息查询
|
||||
*
|
||||
* @param bookId 小说ID
|
||||
* @return 章节相关联的信息
|
||||
*/
|
||||
RestResp<BookChapterAboutRespDto> getLastChapterAbout(Long bookId);
|
||||
|
||||
/**
|
||||
* 小说推荐列表查询
|
||||
*
|
||||
* @param bookId 小说ID
|
||||
* @return 小说信息列表
|
||||
*/
|
||||
RestResp<List<BookInfoRespDto>> listRecBooks(Long bookId) throws NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* 增加小说点击量
|
||||
*
|
||||
* @param bookId 小说ID
|
||||
* @return 成功状态
|
||||
*/
|
||||
RestResp<Void> addVisitCount(Long bookId);
|
||||
|
||||
/**
|
||||
* 获取上一章节ID
|
||||
*
|
||||
* @param chapterId 章节ID
|
||||
* @return 上一章节ID
|
||||
*/
|
||||
RestResp<Long> getPreChapterId(Long chapterId);
|
||||
|
||||
/**
|
||||
* 获取下一章节ID
|
||||
*
|
||||
* @param chapterId 章节ID
|
||||
* @return 下一章节ID
|
||||
*/
|
||||
RestResp<Long> getNextChapterId(Long chapterId);
|
||||
|
||||
/**
|
||||
* 小说章节列表查询
|
||||
*
|
||||
* @param bookId 小说ID
|
||||
* @return 小说章节列表
|
||||
*/
|
||||
RestResp<List<BookChapterRespDto>> listChapters(Long bookId);
|
||||
|
||||
/**
|
||||
* 小说分类列表查询
|
||||
*
|
||||
* @param workDirection 作品方向;0-男频 1-女频
|
||||
* @return 分类列表
|
||||
*/
|
||||
RestResp<List<BookCategoryRespDto>> listCategory(Integer workDirection);
|
||||
|
||||
/**
|
||||
* 发表评论
|
||||
*
|
||||
* @param dto 评论相关 DTO
|
||||
* @return void
|
||||
*/
|
||||
RestResp<Void> saveComment(BookCommentReqDto dto);
|
||||
|
||||
/**
|
||||
* 小说最新评论查询
|
||||
*
|
||||
* @param bookId 小说ID
|
||||
* @return 小说最新评论数据
|
||||
*/
|
||||
RestResp<BookCommentRespDto> listNewestComments(Long bookId);
|
||||
|
||||
/**
|
||||
* 删除评论
|
||||
*
|
||||
* @param dto 评论相关 DTO
|
||||
* @return void
|
||||
*/
|
||||
RestResp<Void> deleteComment(BookCommentReqDto dto);
|
||||
|
||||
/**
|
||||
* 修改评论
|
||||
*
|
||||
* @param dto 评论相关 DTO
|
||||
* @return void
|
||||
*/
|
||||
RestResp<Void> updateComment(BookCommentReqDto dto);
|
||||
|
||||
/**
|
||||
* 小说信息保存
|
||||
*
|
||||
* @param dto 小说信息
|
||||
* @return void
|
||||
*/
|
||||
RestResp<Void> saveBook(BookAddReqDto dto);
|
||||
|
||||
/**
|
||||
* 小说章节信息保存
|
||||
*
|
||||
* @param dto 章节信息
|
||||
* @return void
|
||||
*/
|
||||
RestResp<Void> saveBookChapter(ChapterAddReqDto dto);
|
||||
|
||||
/**
|
||||
* 查询作家发布小说列表
|
||||
*
|
||||
* @param dto 分页请求参数
|
||||
* @return 小说分页列表数据
|
||||
*/
|
||||
RestResp<PageRespDto<BookInfoRespDto>> listAuthorBooks(BookPageReqDto dto);
|
||||
|
||||
/**
|
||||
* 查询小说发布章节列表
|
||||
*
|
||||
* @param dto 分页请求参数
|
||||
* @return 章节分页列表数据
|
||||
*/
|
||||
RestResp<PageRespDto<BookChapterRespDto>> listBookChapters(ChapterPageReqDto dto);
|
||||
|
||||
/**
|
||||
* 查询下一批保存到 ES 中的小说列表
|
||||
*
|
||||
* @param maxBookId 已查询的最大小说ID
|
||||
* @return 小说列表
|
||||
*/
|
||||
RestResp<List<BookEsRespDto>> listNextEsBooks(Long maxBookId);
|
||||
|
||||
/**
|
||||
* 批量查询小说信息
|
||||
*
|
||||
* @param bookIds 小说ID列表
|
||||
* @return 小说信息列表
|
||||
*/
|
||||
RestResp<List<BookInfoRespDto>> listBookInfoByIds(List<Long> bookIds);
|
||||
}
|
||||
@@ -0,0 +1,472 @@
|
||||
package io.github.xxyopen.novel.book.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookChapter;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookComment;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookContent;
|
||||
import io.github.xxyopen.novel.book.dao.entity.BookInfo;
|
||||
import io.github.xxyopen.novel.book.dao.mapper.BookChapterMapper;
|
||||
import io.github.xxyopen.novel.book.dao.mapper.BookCommentMapper;
|
||||
import io.github.xxyopen.novel.book.dao.mapper.BookContentMapper;
|
||||
import io.github.xxyopen.novel.book.dao.mapper.BookInfoMapper;
|
||||
import io.github.xxyopen.novel.book.dto.req.*;
|
||||
import io.github.xxyopen.novel.book.dto.resp.*;
|
||||
import io.github.xxyopen.novel.book.manager.cache.*;
|
||||
import io.github.xxyopen.novel.book.manager.feign.UserFeignManager;
|
||||
import io.github.xxyopen.novel.book.manager.mq.AmqpMsgManager;
|
||||
import io.github.xxyopen.novel.book.service.BookService;
|
||||
import io.github.xxyopen.novel.common.auth.UserHolder;
|
||||
import io.github.xxyopen.novel.common.constant.DatabaseConsts;
|
||||
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 io.github.xxyopen.novel.config.annotation.Key;
|
||||
import io.github.xxyopen.novel.config.annotation.Lock;
|
||||
import io.github.xxyopen.novel.user.dto.resp.UserInfoRespDto;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 小说模块 服务实现类
|
||||
*
|
||||
* @author xiongxiaoyang
|
||||
* @date 2022/5/14
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class BookServiceImpl implements BookService {
|
||||
|
||||
private final BookCategoryCacheManager bookCategoryCacheManager;
|
||||
|
||||
private final BookRankCacheManager bookRankCacheManager;
|
||||
|
||||
private final BookInfoCacheManager bookInfoCacheManager;
|
||||
|
||||
private final BookChapterCacheManager bookChapterCacheManager;
|
||||
|
||||
private final BookContentCacheManager bookContentCacheManager;
|
||||
|
||||
private final BookInfoMapper bookInfoMapper;
|
||||
|
||||
private final BookChapterMapper bookChapterMapper;
|
||||
|
||||
private final BookContentMapper bookContentMapper;
|
||||
|
||||
private final BookCommentMapper bookCommentMapper;
|
||||
|
||||
private final AmqpMsgManager amqpMsgManager;
|
||||
|
||||
private final UserFeignManager userFeignManager;
|
||||
|
||||
private static final Integer REC_BOOK_COUNT = 4;
|
||||
|
||||
@Override
|
||||
public RestResp<List<BookRankRespDto>> listVisitRankBooks() {
|
||||
return RestResp.ok(bookRankCacheManager.listVisitRankBooks());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<List<BookRankRespDto>> listNewestRankBooks() {
|
||||
return RestResp.ok(bookRankCacheManager.listNewestRankBooks());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<List<BookRankRespDto>> listUpdateRankBooks() {
|
||||
return RestResp.ok(bookRankCacheManager.listUpdateRankBooks());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<BookInfoRespDto> getBookById(Long bookId) {
|
||||
return RestResp.ok(bookInfoCacheManager.getBookInfo(bookId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<BookChapterAboutRespDto> getLastChapterAbout(Long bookId) {
|
||||
// 查询小说信息
|
||||
BookInfoRespDto bookInfo = bookInfoCacheManager.getBookInfo(bookId);
|
||||
|
||||
// 查询最新章节信息
|
||||
BookChapterRespDto bookChapter = bookChapterCacheManager.getChapter(
|
||||
bookInfo.getLastChapterId());
|
||||
|
||||
// 查询章节内容
|
||||
String content = bookContentCacheManager.getBookContent(bookInfo.getLastChapterId());
|
||||
|
||||
// 查询章节总数
|
||||
QueryWrapper<BookChapter> chapterQueryWrapper = new QueryWrapper<>();
|
||||
chapterQueryWrapper.eq(DatabaseConsts.BookChapterTable.COLUMN_BOOK_ID, bookId);
|
||||
Long chapterTotal = bookChapterMapper.selectCount(chapterQueryWrapper);
|
||||
|
||||
// 组装数据并返回
|
||||
return RestResp.ok(BookChapterAboutRespDto.builder()
|
||||
.chapterInfo(bookChapter)
|
||||
.chapterTotal(chapterTotal)
|
||||
.contentSummary(content.substring(0, 30))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<List<BookInfoRespDto>> listRecBooks(Long bookId)
|
||||
throws NoSuchAlgorithmException {
|
||||
Long categoryId = bookInfoCacheManager.getBookInfo(bookId).getCategoryId();
|
||||
List<Long> lastUpdateIdList = bookInfoCacheManager.getLastUpdateIdList(categoryId);
|
||||
List<BookInfoRespDto> respDtoList = new ArrayList<>();
|
||||
List<Integer> recIdIndexList = new ArrayList<>();
|
||||
int count = 0;
|
||||
Random rand = SecureRandom.getInstanceStrong();
|
||||
while (count < REC_BOOK_COUNT) {
|
||||
int recIdIndex = rand.nextInt(lastUpdateIdList.size());
|
||||
if (!recIdIndexList.contains(recIdIndex)) {
|
||||
recIdIndexList.add(recIdIndex);
|
||||
bookId = lastUpdateIdList.get(recIdIndex);
|
||||
BookInfoRespDto bookInfo = bookInfoCacheManager.getBookInfo(bookId);
|
||||
respDtoList.add(bookInfo);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return RestResp.ok(respDtoList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<Void> addVisitCount(Long bookId) {
|
||||
bookInfoMapper.addVisitCount(bookId);
|
||||
return RestResp.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<Long> getPreChapterId(Long chapterId) {
|
||||
// 查询小说ID 和 章节号
|
||||
BookChapterRespDto chapter = bookChapterCacheManager.getChapter(chapterId);
|
||||
Long bookId = chapter.getBookId();
|
||||
Integer chapterNum = chapter.getChapterNum();
|
||||
|
||||
// 查询上一章信息并返回章节ID
|
||||
QueryWrapper<BookChapter> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq(DatabaseConsts.BookChapterTable.COLUMN_BOOK_ID, bookId)
|
||||
.lt(DatabaseConsts.BookChapterTable.COLUMN_CHAPTER_NUM, chapterNum)
|
||||
.orderByDesc(DatabaseConsts.BookChapterTable.COLUMN_CHAPTER_NUM)
|
||||
.last(DatabaseConsts.SqlEnum.LIMIT_1.getSql());
|
||||
return RestResp.ok(
|
||||
Optional.ofNullable(bookChapterMapper.selectOne(queryWrapper))
|
||||
.map(BookChapter::getId)
|
||||
.orElse(null)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<Long> getNextChapterId(Long chapterId) {
|
||||
// 查询小说ID 和 章节号
|
||||
BookChapterRespDto chapter = bookChapterCacheManager.getChapter(chapterId);
|
||||
Long bookId = chapter.getBookId();
|
||||
Integer chapterNum = chapter.getChapterNum();
|
||||
|
||||
// 查询下一章信息并返回章节ID
|
||||
QueryWrapper<BookChapter> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq(DatabaseConsts.BookChapterTable.COLUMN_BOOK_ID, bookId)
|
||||
.gt(DatabaseConsts.BookChapterTable.COLUMN_CHAPTER_NUM, chapterNum)
|
||||
.orderByAsc(DatabaseConsts.BookChapterTable.COLUMN_CHAPTER_NUM)
|
||||
.last(DatabaseConsts.SqlEnum.LIMIT_1.getSql());
|
||||
return RestResp.ok(
|
||||
Optional.ofNullable(bookChapterMapper.selectOne(queryWrapper))
|
||||
.map(BookChapter::getId)
|
||||
.orElse(null)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<List<BookChapterRespDto>> listChapters(Long bookId) {
|
||||
QueryWrapper<BookChapter> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq(DatabaseConsts.BookChapterTable.COLUMN_BOOK_ID, bookId)
|
||||
.orderByAsc(DatabaseConsts.BookChapterTable.COLUMN_CHAPTER_NUM);
|
||||
return RestResp.ok(bookChapterMapper.selectList(queryWrapper).stream()
|
||||
.map(v -> BookChapterRespDto.builder()
|
||||
.id(v.getId())
|
||||
.chapterName(v.getChapterName())
|
||||
.isVip(v.getIsVip())
|
||||
.build()).toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<List<BookCategoryRespDto>> listCategory(Integer workDirection) {
|
||||
return RestResp.ok(bookCategoryCacheManager.listCategory(workDirection));
|
||||
}
|
||||
|
||||
@Lock(prefix = "userComment")
|
||||
@Override
|
||||
public RestResp<Void> saveComment(
|
||||
@Key(expr = "#{userId + '::' + bookId}") BookCommentReqDto dto) {
|
||||
// 校验用户是否已发表评论
|
||||
QueryWrapper<BookComment> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq(DatabaseConsts.BookCommentTable.COLUMN_USER_ID, dto.getUserId())
|
||||
.eq(DatabaseConsts.BookCommentTable.COLUMN_BOOK_ID, dto.getBookId());
|
||||
if (bookCommentMapper.selectCount(queryWrapper) > 0) {
|
||||
// 用户已发表评论
|
||||
return RestResp.fail(ErrorCodeEnum.USER_COMMENTED);
|
||||
}
|
||||
BookComment bookComment = new BookComment();
|
||||
bookComment.setBookId(dto.getBookId());
|
||||
bookComment.setUserId(dto.getUserId());
|
||||
bookComment.setCommentContent(dto.getCommentContent());
|
||||
bookComment.setCreateTime(LocalDateTime.now());
|
||||
bookComment.setUpdateTime(LocalDateTime.now());
|
||||
bookCommentMapper.insert(bookComment);
|
||||
return RestResp.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<BookCommentRespDto> listNewestComments(Long bookId) {
|
||||
// 查询评论总数
|
||||
QueryWrapper<BookComment> commentCountQueryWrapper = new QueryWrapper<>();
|
||||
commentCountQueryWrapper.eq(DatabaseConsts.BookCommentTable.COLUMN_BOOK_ID, bookId);
|
||||
Long commentTotal = bookCommentMapper.selectCount(commentCountQueryWrapper);
|
||||
BookCommentRespDto bookCommentRespDto = BookCommentRespDto.builder()
|
||||
.commentTotal(commentTotal).build();
|
||||
if (commentTotal > 0) {
|
||||
|
||||
// 查询最新的评论列表
|
||||
QueryWrapper<BookComment> commentQueryWrapper = new QueryWrapper<>();
|
||||
commentQueryWrapper.eq(DatabaseConsts.BookCommentTable.COLUMN_BOOK_ID, bookId)
|
||||
.orderByDesc(DatabaseConsts.CommonColumnEnum.CREATE_TIME.getName())
|
||||
.last(DatabaseConsts.SqlEnum.LIMIT_5.getSql());
|
||||
List<BookComment> bookComments = bookCommentMapper.selectList(commentQueryWrapper);
|
||||
|
||||
// 查询评论用户信息,并设置需要返回的评论用户名
|
||||
List<Long> userIds = bookComments.stream().map(BookComment::getUserId).toList();
|
||||
List<UserInfoRespDto> userInfos = userFeignManager.listUserInfoByIds(userIds);
|
||||
Map<Long, UserInfoRespDto> userInfoMap = userInfos.stream()
|
||||
.collect(Collectors.toMap(UserInfoRespDto::getId, Function.identity()));
|
||||
List<BookCommentRespDto.CommentInfo> commentInfos = bookComments.stream()
|
||||
.map(v -> BookCommentRespDto.CommentInfo.builder()
|
||||
.id(v.getId())
|
||||
.commentUserId(v.getUserId())
|
||||
.commentUser(userInfoMap.get(v.getUserId()).getUsername())
|
||||
.commentUserPhoto(userInfoMap.get(v.getUserId()).getUserPhoto())
|
||||
.commentContent(v.getCommentContent())
|
||||
.commentTime(v.getCreateTime()).build()).toList();
|
||||
bookCommentRespDto.setComments(commentInfos);
|
||||
} else {
|
||||
bookCommentRespDto.setComments(Collections.emptyList());
|
||||
}
|
||||
return RestResp.ok(bookCommentRespDto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<Void> deleteComment(BookCommentReqDto dto) {
|
||||
QueryWrapper<BookComment> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq(DatabaseConsts.CommonColumnEnum.ID.getName(), dto.getCommentId())
|
||||
.eq(DatabaseConsts.BookCommentTable.COLUMN_USER_ID, dto.getUserId());
|
||||
bookCommentMapper.delete(queryWrapper);
|
||||
return RestResp.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<Void> updateComment(BookCommentReqDto dto) {
|
||||
QueryWrapper<BookComment> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq(DatabaseConsts.CommonColumnEnum.ID.getName(), dto.getCommentId())
|
||||
.eq(DatabaseConsts.BookCommentTable.COLUMN_USER_ID, dto.getUserId());
|
||||
BookComment bookComment = new BookComment();
|
||||
bookComment.setCommentContent(dto.getCommentContent());
|
||||
bookCommentMapper.update(bookComment, queryWrapper);
|
||||
return RestResp.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<Void> saveBook(BookAddReqDto dto) {
|
||||
// 校验小说名是否已存在
|
||||
QueryWrapper<BookInfo> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq(DatabaseConsts.BookTable.COLUMN_BOOK_NAME, dto.getBookName());
|
||||
if (bookInfoMapper.selectCount(queryWrapper) > 0) {
|
||||
return RestResp.fail(ErrorCodeEnum.AUTHOR_BOOK_NAME_EXIST);
|
||||
}
|
||||
BookInfo bookInfo = new BookInfo();
|
||||
// 设置作家信息
|
||||
bookInfo.setAuthorId(dto.getAuthorId());
|
||||
bookInfo.setAuthorName(dto.getPenName());
|
||||
// 设置其他信息
|
||||
bookInfo.setWorkDirection(dto.getWorkDirection());
|
||||
bookInfo.setCategoryId(dto.getCategoryId());
|
||||
bookInfo.setCategoryName(dto.getCategoryName());
|
||||
bookInfo.setBookName(dto.getBookName());
|
||||
bookInfo.setPicUrl(dto.getPicUrl());
|
||||
bookInfo.setBookDesc(dto.getBookDesc());
|
||||
bookInfo.setIsVip(dto.getIsVip());
|
||||
bookInfo.setScore(0);
|
||||
bookInfo.setCreateTime(LocalDateTime.now());
|
||||
bookInfo.setUpdateTime(LocalDateTime.now());
|
||||
// 保存小说信息
|
||||
bookInfoMapper.insert(bookInfo);
|
||||
return RestResp.ok();
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public RestResp<Void> saveBookChapter(ChapterAddReqDto dto) {
|
||||
// 校验该作品是否属于当前作家
|
||||
BookInfo bookInfo = bookInfoMapper.selectById(dto.getBookId());
|
||||
if (!Objects.equals(bookInfo.getAuthorId(), dto.getAuthorId())) {
|
||||
return RestResp.fail(ErrorCodeEnum.USER_UN_AUTH);
|
||||
}
|
||||
// 1) 保存章节相关信息到小说章节表
|
||||
// a) 查询最新章节号
|
||||
int chapterNum = 0;
|
||||
QueryWrapper<BookChapter> chapterQueryWrapper = new QueryWrapper<>();
|
||||
chapterQueryWrapper.eq(DatabaseConsts.BookChapterTable.COLUMN_BOOK_ID, dto.getBookId())
|
||||
.orderByDesc(DatabaseConsts.BookChapterTable.COLUMN_CHAPTER_NUM)
|
||||
.last(DatabaseConsts.SqlEnum.LIMIT_1.getSql());
|
||||
BookChapter bookChapter = bookChapterMapper.selectOne(chapterQueryWrapper);
|
||||
if (Objects.nonNull(bookChapter)) {
|
||||
chapterNum = bookChapter.getChapterNum() + 1;
|
||||
}
|
||||
// b) 设置章节相关信息并保存
|
||||
BookChapter newBookChapter = new BookChapter();
|
||||
newBookChapter.setBookId(dto.getBookId());
|
||||
newBookChapter.setChapterName(dto.getChapterName());
|
||||
newBookChapter.setChapterNum(chapterNum);
|
||||
newBookChapter.setWordCount(dto.getChapterContent().length());
|
||||
newBookChapter.setIsVip(dto.getIsVip());
|
||||
newBookChapter.setCreateTime(LocalDateTime.now());
|
||||
newBookChapter.setUpdateTime(LocalDateTime.now());
|
||||
bookChapterMapper.insert(newBookChapter);
|
||||
|
||||
// 2) 保存章节内容到小说内容表
|
||||
BookContent bookContent = new BookContent();
|
||||
bookContent.setContent(dto.getChapterContent());
|
||||
bookContent.setChapterId(newBookChapter.getId());
|
||||
bookContent.setCreateTime(LocalDateTime.now());
|
||||
bookContent.setUpdateTime(LocalDateTime.now());
|
||||
bookContentMapper.insert(bookContent);
|
||||
|
||||
// 3) 更新小说表最新章节信息和小说总字数信息
|
||||
// a) 更新小说表关于最新章节的信息
|
||||
BookInfo newBookInfo = new BookInfo();
|
||||
newBookInfo.setId(dto.getBookId());
|
||||
newBookInfo.setLastChapterId(newBookChapter.getId());
|
||||
newBookInfo.setLastChapterName(newBookChapter.getChapterName());
|
||||
newBookInfo.setLastChapterUpdateTime(LocalDateTime.now());
|
||||
newBookInfo.setWordCount(bookInfo.getWordCount() + newBookChapter.getWordCount());
|
||||
newBookChapter.setUpdateTime(LocalDateTime.now());
|
||||
bookInfoMapper.updateById(newBookInfo);
|
||||
// b) 清除小说信息缓存
|
||||
bookInfoCacheManager.evictBookInfoCache(dto.getBookId());
|
||||
// c) 发送小说信息更新的 MQ 消息
|
||||
amqpMsgManager.sendBookChangeMsg(dto.getBookId());
|
||||
return RestResp.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<PageRespDto<BookInfoRespDto>> listAuthorBooks(BookPageReqDto dto) {
|
||||
IPage<BookInfo> page = new Page<>();
|
||||
page.setCurrent(dto.getPageNum());
|
||||
page.setSize(dto.getPageSize());
|
||||
QueryWrapper<BookInfo> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq(DatabaseConsts.BookTable.AUTHOR_ID, dto.getAuthorId())
|
||||
.orderByDesc(DatabaseConsts.CommonColumnEnum.CREATE_TIME.getName());
|
||||
IPage<BookInfo> bookInfoPage = bookInfoMapper.selectPage(page, queryWrapper);
|
||||
return RestResp.ok(PageRespDto.of(dto.getPageNum(), dto.getPageSize(), page.getTotal(),
|
||||
bookInfoPage.getRecords().stream().map(v -> BookInfoRespDto.builder()
|
||||
.id(v.getId())
|
||||
.bookName(v.getBookName())
|
||||
.picUrl(v.getPicUrl())
|
||||
.categoryName(v.getCategoryName())
|
||||
.wordCount(v.getWordCount())
|
||||
.visitCount(v.getVisitCount())
|
||||
.updateTime(v.getUpdateTime())
|
||||
.build()).toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<PageRespDto<BookChapterRespDto>> listBookChapters(ChapterPageReqDto dto) {
|
||||
IPage<BookChapter> page = new Page<>();
|
||||
page.setCurrent(dto.getPageNum());
|
||||
page.setSize(dto.getPageSize());
|
||||
QueryWrapper<BookChapter> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq(DatabaseConsts.BookChapterTable.COLUMN_BOOK_ID, dto.getBookId())
|
||||
.orderByDesc(DatabaseConsts.BookChapterTable.COLUMN_CHAPTER_NUM);
|
||||
IPage<BookChapter> bookChapterPage = bookChapterMapper.selectPage(page, queryWrapper);
|
||||
return RestResp.ok(PageRespDto.of(dto.getPageNum(), dto.getPageSize(), page.getTotal(),
|
||||
bookChapterPage.getRecords().stream().map(v -> BookChapterRespDto.builder()
|
||||
.id(v.getId())
|
||||
.chapterName(v.getChapterName())
|
||||
.chapterUpdateTime(v.getUpdateTime())
|
||||
.isVip(v.getIsVip())
|
||||
.build()).toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<List<BookEsRespDto>> listNextEsBooks(Long maxBookId) {
|
||||
QueryWrapper<BookInfo> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.clear();
|
||||
queryWrapper
|
||||
.orderByAsc(DatabaseConsts.CommonColumnEnum.ID.getName())
|
||||
.gt(DatabaseConsts.CommonColumnEnum.ID.getName(), maxBookId)
|
||||
.gt(DatabaseConsts.BookTable.COLUMN_WORD_COUNT, 0)
|
||||
.last(DatabaseConsts.SqlEnum.LIMIT_30.getSql());
|
||||
return RestResp.ok(bookInfoMapper.selectList(queryWrapper).stream().map(bookInfo -> BookEsRespDto.builder()
|
||||
.id(bookInfo.getId())
|
||||
.categoryId(bookInfo.getCategoryId())
|
||||
.categoryName(bookInfo.getCategoryName())
|
||||
.bookDesc(bookInfo.getBookDesc())
|
||||
.bookName(bookInfo.getBookName())
|
||||
.authorId(bookInfo.getAuthorId())
|
||||
.authorName(bookInfo.getAuthorName())
|
||||
.bookStatus(bookInfo.getBookStatus())
|
||||
.commentCount(bookInfo.getCommentCount())
|
||||
.isVip(bookInfo.getIsVip())
|
||||
.score(bookInfo.getScore())
|
||||
.visitCount(bookInfo.getVisitCount())
|
||||
.wordCount(bookInfo.getWordCount())
|
||||
.workDirection(bookInfo.getWorkDirection())
|
||||
.lastChapterId(bookInfo.getLastChapterId())
|
||||
.lastChapterName(bookInfo.getLastChapterName())
|
||||
.lastChapterUpdateTime(bookInfo.getLastChapterUpdateTime()
|
||||
.toInstant(ZoneOffset.ofHours(8)).toEpochMilli())
|
||||
.build()).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<List<BookInfoRespDto>> listBookInfoByIds(List<Long> bookIds) {
|
||||
QueryWrapper<BookInfo> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.in(DatabaseConsts.CommonColumnEnum.ID.getName(), bookIds);
|
||||
return RestResp.ok(
|
||||
bookInfoMapper.selectList(queryWrapper).stream().map(v -> BookInfoRespDto.builder()
|
||||
.id(v.getId())
|
||||
.bookName(v.getBookName())
|
||||
.authorName(v.getAuthorName())
|
||||
.picUrl(v.getPicUrl())
|
||||
.bookDesc(v.getBookDesc())
|
||||
.build()).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResp<BookContentAboutRespDto> getBookContentAbout(Long chapterId) {
|
||||
log.debug("userId:{}", UserHolder.getUserId());
|
||||
// 查询章节信息
|
||||
BookChapterRespDto bookChapter = bookChapterCacheManager.getChapter(chapterId);
|
||||
|
||||
// 查询章节内容
|
||||
String content = bookContentCacheManager.getBookContent(chapterId);
|
||||
|
||||
// 查询小说信息
|
||||
BookInfoRespDto bookInfo = bookInfoCacheManager.getBookInfo(bookChapter.getBookId());
|
||||
|
||||
// 组装数据并返回
|
||||
return RestResp.ok(BookContentAboutRespDto.builder()
|
||||
.bookInfo(bookInfo)
|
||||
.chapterInfo(bookChapter)
|
||||
.bookContent(content)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
server:
|
||||
port: 9020
|
||||
spring:
|
||||
profiles:
|
||||
include: common
|
||||
active: dev
|
||||
|
||||
management:
|
||||
# 端点启用配置
|
||||
endpoint:
|
||||
logfile:
|
||||
# 启用返回日志文件内容的端点
|
||||
enabled: true
|
||||
# 外部日志文件路径
|
||||
external-file: logs/novel-book-service.log
|
||||
@@ -0,0 +1,6 @@
|
||||
spring:
|
||||
application:
|
||||
name: novel-book-service
|
||||
profiles:
|
||||
include: common
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<!-- 彩色日志依赖的渲染类 -->
|
||||
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
|
||||
<conversionRule conversionWord="wex"
|
||||
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
|
||||
<conversionRule conversionWord="wEx"
|
||||
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
|
||||
<!-- 彩色日志格式 -->
|
||||
<property name="CONSOLE_LOG_PATTERN"
|
||||
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
|
||||
|
||||
<!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%i索引【从数字0开始递增】,,, -->
|
||||
<!-- appender是configuration的子节点,是负责写日志的组件。 -->
|
||||
<!-- ConsoleAppender:把日志输出到控制台 -->
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
|
||||
<!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
|
||||
<!-- 以下的大概意思是:1.先按日期存日志,日期变了,将前一天的日志文件名重命名为XXX%日期%索引,新的日志仍然是demo.log -->
|
||||
<!-- 2.如果日期没有发生变化,但是当前日志的文件大小超过1KB时,对当前日志进行分割 重命名 -->
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
|
||||
<File>logs/novel-book-service.log</File>
|
||||
<!-- rollingPolicy:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
|
||||
<!-- TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 活动文件的名字会根据fileNamePattern的值,每隔一段时间改变一次 -->
|
||||
<!-- 文件名:logs/demo.2017-12-05.0.log -->
|
||||
<fileNamePattern>logs/debug.%d.%i.log</fileNamePattern>
|
||||
<!-- 每产生一个日志文件,该日志文件的保存期限为30天 -->
|
||||
<maxHistory>30</maxHistory>
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<!-- maxFileSize:这是活动文件的大小,默认值是10MB,测试时可改成1KB看效果 -->
|
||||
<maxFileSize>10MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<!-- pattern节点,用来设置日志的输入格式 -->
|
||||
<pattern>
|
||||
%d %p (%file:%line\)- %m%n
|
||||
</pattern>
|
||||
<!-- 记录日志的编码:此处设置字符集 - -->
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
<springProfile name="dev">
|
||||
<!-- ROOT 日志级别 -->
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
</root>
|
||||
<!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
|
||||
<!-- com.maijinjie.springboot 为根包,也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG -->
|
||||
<!-- 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE -->
|
||||
<logger name="io.github.xxyopen" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
</logger>
|
||||
</springProfile>
|
||||
|
||||
<springProfile name="prod">
|
||||
<!-- ROOT 日志级别 -->
|
||||
<root level="INFO">
|
||||
<appender-ref ref="FILE"/>
|
||||
</root>
|
||||
<!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
|
||||
<!-- com.maijinjie.springboot 为根包,也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG -->
|
||||
<!-- 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE -->
|
||||
<logger name="io.github.xxyopen" level="ERROR" additivity="false">
|
||||
<appender-ref ref="FILE"/>
|
||||
</logger>
|
||||
</springProfile>
|
||||
</configuration>
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="io.github.xxyopen.novel.book.dao.mapper.BookInfoMapper">
|
||||
|
||||
<select id="searchBooks" resultType="io.github.xxyopen.novel.book.dao.entity.BookInfo">
|
||||
select
|
||||
id,category_id,category_name,book_name,author_id,author_name,word_count,last_chapter_name
|
||||
from book_info where word_count > 0
|
||||
<if test="condition.keyword != null and condition.keyword != ''">
|
||||
and (book_name like concat('%',#{condition.keyword},'%') or author_name like
|
||||
concat('%',#{condition.keyword},'%'))
|
||||
</if>
|
||||
<if test="condition.workDirection != null">
|
||||
and work_direction = #{condition.workDirection}
|
||||
</if>
|
||||
<if test="condition.categoryId != null">
|
||||
and category_id = #{condition.categoryId}
|
||||
</if>
|
||||
<if test="condition.isVip != null">
|
||||
and is_vip = #{condition.isVip}
|
||||
</if>
|
||||
<if test="condition.bookStatus != null">
|
||||
and book_status = #{condition.bookStatus}
|
||||
</if>
|
||||
<if test="condition.wordCountMin != null">
|
||||
and word_count >= #{condition.wordCountMin}
|
||||
</if>
|
||||
<if test="condition.wordCountMax != null">
|
||||
and word_count <![CDATA[ < ]]> #{condition.wordCountMax}
|
||||
</if>
|
||||
<if test="condition.updateTimeMin != null">
|
||||
and last_chapter_update_time >= #{condition.updateTimeMin}
|
||||
</if>
|
||||
<if test="condition.sort != null">
|
||||
order by ${condition.sort}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<update id="addVisitCount">
|
||||
update book_info
|
||||
set visit_count = visit_count + 1
|
||||
where id = #{bookId}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user