diff --git a/src/main/java/io/github/xxyopen/novel/controller/author/AuthorController.java b/src/main/java/io/github/xxyopen/novel/controller/author/AuthorController.java index ca5ef90..f311881 100644 --- a/src/main/java/io/github/xxyopen/novel/controller/author/AuthorController.java +++ b/src/main/java/io/github/xxyopen/novel/controller/author/AuthorController.java @@ -5,6 +5,7 @@ import io.github.xxyopen.novel.core.common.resp.RestResp; import io.github.xxyopen.novel.core.constant.ApiRouterConsts; import io.github.xxyopen.novel.dto.req.AuthorRegisterReqDto; import io.github.xxyopen.novel.dto.req.BookAddReqDto; +import io.github.xxyopen.novel.dto.req.ChapterAddReqDto; import io.github.xxyopen.novel.service.AuthorService; import io.github.xxyopen.novel.service.BookService; import jakarta.validation.Valid; @@ -45,4 +46,12 @@ public class AuthorController { return bookService.saveBook(dto); } + /** + * 小说章节发布接口 + */ + @PostMapping("book/chapter") + public RestResp publishBookChapter(@Valid @RequestBody ChapterAddReqDto dto) { + return bookService.saveBookChapter(dto); + } + } diff --git a/src/main/java/io/github/xxyopen/novel/dto/req/ChapterAddReqDto.java b/src/main/java/io/github/xxyopen/novel/dto/req/ChapterAddReqDto.java new file mode 100644 index 0000000..b7ec4ec --- /dev/null +++ b/src/main/java/io/github/xxyopen/novel/dto/req/ChapterAddReqDto.java @@ -0,0 +1,42 @@ +package io.github.xxyopen.novel.dto.req; + +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 + */ + @NotNull + private Long bookId; + + /** + * 章节名 + */ + @NotBlank + private String chapterName; + + /** + * 章节内容 + */ + @NotBlank + @Length(min = 50) + private String chapterContent; + + /** + * 是否收费;1-收费 0-免费 + */ + @NotNull + private Integer isVip; + +} diff --git a/src/main/java/io/github/xxyopen/novel/manager/BookInfoCacheManager.java b/src/main/java/io/github/xxyopen/novel/manager/BookInfoCacheManager.java index 0320409..00c1686 100644 --- a/src/main/java/io/github/xxyopen/novel/manager/BookInfoCacheManager.java +++ b/src/main/java/io/github/xxyopen/novel/manager/BookInfoCacheManager.java @@ -9,6 +9,7 @@ import io.github.xxyopen.novel.dao.mapper.BookChapterMapper; import io.github.xxyopen.novel.dao.mapper.BookInfoMapper; import io.github.xxyopen.novel.dto.resp.BookInfoRespDto; import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Component; @@ -29,11 +30,20 @@ public class BookInfoCacheManager { 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 @@ -62,6 +72,8 @@ public class BookInfoCacheManager { .build(); } + + /** * 查询每个类别下最新更新的 500 个小说ID列表,并放入缓存中 1 个小时 */ diff --git a/src/main/java/io/github/xxyopen/novel/service/BookService.java b/src/main/java/io/github/xxyopen/novel/service/BookService.java index c236603..634c422 100644 --- a/src/main/java/io/github/xxyopen/novel/service/BookService.java +++ b/src/main/java/io/github/xxyopen/novel/service/BookService.java @@ -4,6 +4,7 @@ import io.github.xxyopen.novel.core.common.resp.PageRespDto; import io.github.xxyopen.novel.core.common.resp.RestResp; import io.github.xxyopen.novel.dto.req.BookAddReqDto; import io.github.xxyopen.novel.dto.req.BookSearchReqDto; +import io.github.xxyopen.novel.dto.req.ChapterAddReqDto; import io.github.xxyopen.novel.dto.req.UserCommentReqDto; import io.github.xxyopen.novel.dto.resp.*; @@ -153,9 +154,16 @@ public interface BookService { RestResp updateComment(Long userId, Long id, String content); /** - * 小说发布 + * 小说信息保存 * @param dto 小说信息 * @return void * */ RestResp saveBook(BookAddReqDto dto); + + /** + * 小说章节信息保存 + * @param dto 章节信息 + * @return void + * */ + RestResp saveBookChapter(ChapterAddReqDto dto); } diff --git a/src/main/java/io/github/xxyopen/novel/service/impl/BookServiceImpl.java b/src/main/java/io/github/xxyopen/novel/service/impl/BookServiceImpl.java index d82035f..073180a 100644 --- a/src/main/java/io/github/xxyopen/novel/service/impl/BookServiceImpl.java +++ b/src/main/java/io/github/xxyopen/novel/service/impl/BookServiceImpl.java @@ -10,10 +10,12 @@ import io.github.xxyopen.novel.core.constant.DatabaseConsts; import io.github.xxyopen.novel.dao.entity.*; import io.github.xxyopen.novel.dao.mapper.BookChapterMapper; import io.github.xxyopen.novel.dao.mapper.BookCommentMapper; +import io.github.xxyopen.novel.dao.mapper.BookContentMapper; import io.github.xxyopen.novel.dao.mapper.BookInfoMapper; import io.github.xxyopen.novel.dto.AuthorInfoDto; import io.github.xxyopen.novel.dto.req.BookAddReqDto; import io.github.xxyopen.novel.dto.req.BookSearchReqDto; +import io.github.xxyopen.novel.dto.req.ChapterAddReqDto; import io.github.xxyopen.novel.dto.req.UserCommentReqDto; import io.github.xxyopen.novel.dto.resp.*; import io.github.xxyopen.novel.manager.*; @@ -21,6 +23,7 @@ import io.github.xxyopen.novel.service.BookService; 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; @@ -56,6 +59,8 @@ public class BookServiceImpl implements BookService { private final BookChapterMapper bookChapterMapper; + private final BookContentMapper bookContentMapper; + private final BookCommentMapper bookCommentMapper; private final UserDaoManager userDaoManager; @@ -306,6 +311,55 @@ public class BookServiceImpl implements BookService { return RestResp.ok(); } + @Transactional(rollbackFor = Exception.class) + @Override + public RestResp saveBookChapter(ChapterAddReqDto dto) { + // 1) 保存章节相关信息到小说章节表 + // a) 查询最新章节号 + int chapterNum = 0; + QueryWrapper 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) 更新小说表关于最新章节的信息 + BookInfoRespDto bookInfo = bookInfoCacheManager.getBookInfo(dto.getBookId()); + 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.cachePutBookInfo(dto.getBookId()); + return RestResp.ok(); + } + @Override public RestResp getBookContentAbout(Long chapterId) { // 查询章节信息