增加小说内容TXT文本存储方案(一行配置切换)

This commit is contained in:
xiaoyang 2021-08-17 19:55:24 +08:00
parent cbfd0b049f
commit 750c8dee02
12 changed files with 262 additions and 54 deletions

View File

@ -19,6 +19,7 @@ import java.util.Objects;
/** /**
* 文件操作工具类 * 文件操作工具类
*
* @author 11797 * @author 11797
*/ */
@UtilityClass @UtilityClass
@ -27,8 +28,8 @@ public class FileUtil {
/** /**
* 网络图片转本地 * 网络图片转本地
* */ */
public String network2Local(String picSrc,String picSavePath,String visitPrefix) { public String network2Local(String picSrc, String picSavePath, String visitPrefix) {
InputStream input = null; InputStream input = null;
OutputStream out = null; OutputStream out = null;
try { try {
@ -53,45 +54,41 @@ public class FileUtil {
} }
out.flush(); out.flush();
if( ImageIO.read(picFile) == null){ if (ImageIO.read(picFile) == null) {
picSrc = "/images/default.gif"; picSrc = "/images/default.gif";
} }
}catch (Exception e){ } catch (Exception e) {
log.error(e.getMessage(),e); log.error(e.getMessage(), e);
picSrc = "/images/default.gif"; picSrc = "/images/default.gif";
}finally { } finally {
if(input != null){ closeStream(input, out);
try {
input.close();
} catch (IOException e) {
log.error(e.getMessage(),e);
}finally {
if(out != null){
try {
out.close();
} catch (IOException e) {
log.error(e.getMessage(),e);
}
}
}
}
} }
return picSrc; return picSrc;
} }
@SneakyThrows
private void closeStream(InputStream input, OutputStream out) {
if (input != null) {
input.close();
}
if (out != null) {
out.close();
}
}
/** /**
* 判断文件是否为图片 * 判断文件是否为图片
*
* @param file 需要判断的文件 * @param file 需要判断的文件
* @return true:是图片false:不是图片 * @return true:是图片false:不是图片
* */ */
@SneakyThrows @SneakyThrows
public boolean isImage(File file){ public boolean isImage(File file) {
BufferedImage bi = ImageIO.read(file); BufferedImage bi = ImageIO.read(file);
@ -100,6 +97,27 @@ public class FileUtil {
} }
public void writeContentToFile(String fileSavePath, String fileSrc, String content) {
OutputStream out = null;
try {
File file = new File(fileSavePath + fileSrc);
File parentFile = file.getParentFile();
if (!parentFile.exists()) {
parentFile.mkdirs();
}
out = new FileOutputStream(file);
out.write(content.getBytes());
byte[] b = new byte[4096];
out.flush();
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new RuntimeException("文件写入失败");
} finally {
closeStream(null, out);
}
}
} }

View File

@ -71,3 +71,7 @@ sharding:
txt:
save:
storage: db #存储介质db数据库filetxt文本
path: /Users/xiongxiaoyang/books #txt小说文本保存路径

View File

@ -74,7 +74,10 @@ logging:
txt:
save:
storage: db #存储介质db数据库filetxt文本
path: /Users/xiongxiaoyang/books #txt小说文本保存路径

View File

@ -44,7 +44,7 @@
</javaClientGenerator> </javaClientGenerator>
<!--生成全部表tableName设为%--> <!--生成全部表tableName设为%-->
<table tableName="news"/> <table tableName="book_index"/>
<!-- 指定数据库表 --> <!-- 指定数据库表 -->
<!--<table schema="jly" tableName="job_position" domainObjectName="JobPositionTest"/>--> <!--<table schema="jly" tableName="job_position" domainObjectName="JobPositionTest"/>-->

View File

@ -0,0 +1,16 @@
package com.java2nb.novel.service;
import com.java2nb.novel.entity.BookContent;
import java.util.List;
public interface BookContentService {
void saveBookContent(List<BookContent> bookContentList,Long bookId);
void saveBookContent(BookContent bookContent,Long bookId);
void updateBookContent(BookContent bookContent,Long bookId);
}

View File

@ -4,6 +4,7 @@ import com.java2nb.novel.entity.Book;
import com.java2nb.novel.entity.BookContent; import com.java2nb.novel.entity.BookContent;
import com.java2nb.novel.entity.BookIndex; import com.java2nb.novel.entity.BookIndex;
import com.java2nb.novel.mapper.*; import com.java2nb.novel.mapper.*;
import com.java2nb.novel.service.BookContentService;
import com.java2nb.novel.service.BookService; import com.java2nb.novel.service.BookService;
import com.java2nb.novel.utils.Constants; import com.java2nb.novel.utils.Constants;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -37,7 +38,7 @@ public class BookServiceImpl implements BookService {
private final CrawlBookIndexMapper bookIndexMapper; private final CrawlBookIndexMapper bookIndexMapper;
private final BookContentMapper bookContentMapper; private final BookContentService bookContentService;
@Override @Override
@ -46,7 +47,7 @@ public class BookServiceImpl implements BookService {
return bookMapper.count(countFrom(BookDynamicSqlSupport.book).where(BookDynamicSqlSupport.bookName, isEqualTo(bookName)) return bookMapper.count(countFrom(BookDynamicSqlSupport.book).where(BookDynamicSqlSupport.bookName, isEqualTo(bookName))
.and(BookDynamicSqlSupport.authorName, isEqualTo(authorName)) .and(BookDynamicSqlSupport.authorName, isEqualTo(authorName))
.build() .build()
.render(RenderingStrategies.MYBATIS3))>0; .render(RenderingStrategies.MYBATIS3)) > 0;
} }
@ -57,7 +58,7 @@ public class BookServiceImpl implements BookService {
.equalTo(sourceId) .equalTo(sourceId)
.set(crawlBookId) .set(crawlBookId)
.equalTo(bookId) .equalTo(bookId)
.where(BookDynamicSqlSupport.id,isEqualTo(id)) .where(BookDynamicSqlSupport.id, isEqualTo(id))
.build() .build()
.render(RenderingStrategies.MYBATIS3)); .render(RenderingStrategies.MYBATIS3));
} }
@ -74,9 +75,9 @@ public class BookServiceImpl implements BookService {
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@Override @Override
public void saveBookAndIndexAndContent(Book book, List<BookIndex> bookIndexList, List<BookContent> bookContentList) { public void saveBookAndIndexAndContent(Book book, List<BookIndex> bookIndexList, List<BookContent> bookContentList) {
if(!queryIsExistByBookNameAndAuthorName(book.getBookName(),book.getAuthorName())) { if (!queryIsExistByBookNameAndAuthorName(book.getBookName(), book.getAuthorName())) {
if(bookIndexList.size()>0) { if (bookIndexList.size() > 0) {
//保存小说主表 //保存小说主表
@ -85,7 +86,7 @@ public class BookServiceImpl implements BookService {
//批量保存目录和内容 //批量保存目录和内容
bookIndexMapper.insertMultiple(bookIndexList); bookIndexMapper.insertMultiple(bookIndexList);
bookContentMapper.insertMultiple(bookContentList); bookContentService.saveBookContent(bookContentList,book.getId());
} }
} }
@ -96,7 +97,7 @@ public class BookServiceImpl implements BookService {
@Override @Override
public List<Book> queryNeedUpdateBook(Date startDate, int limit) { public List<Book> queryNeedUpdateBook(Date startDate, int limit) {
List<Book> books = bookMapper.queryNeedUpdateBook(startDate, limit); List<Book> books = bookMapper.queryNeedUpdateBook(startDate, limit);
if(books.size()>0) { if (books.size() > 0) {
//更新最后抓取时间为当前时间 //更新最后抓取时间为当前时间
bookMapper.updateCrawlLastTime(books, new Date()); bookMapper.updateCrawlLastTime(books, new Date());
} }
@ -105,38 +106,33 @@ public class BookServiceImpl implements BookService {
@Override @Override
public Map<Integer, BookIndex> queryExistBookIndexMap(Long bookId) { public Map<Integer, BookIndex> queryExistBookIndexMap(Long bookId) {
List<BookIndex> bookIndexs = bookIndexMapper.selectMany(select(BookIndexDynamicSqlSupport.id,BookIndexDynamicSqlSupport.indexNum,BookIndexDynamicSqlSupport.indexName,BookIndexDynamicSqlSupport.wordCount) List<BookIndex> bookIndexs = bookIndexMapper.selectMany(select(BookIndexDynamicSqlSupport.id, BookIndexDynamicSqlSupport.indexNum, BookIndexDynamicSqlSupport.indexName, BookIndexDynamicSqlSupport.wordCount)
.from(BookIndexDynamicSqlSupport.bookIndex) .from(BookIndexDynamicSqlSupport.bookIndex)
.where(BookIndexDynamicSqlSupport.bookId,isEqualTo(bookId)) .where(BookIndexDynamicSqlSupport.bookId, isEqualTo(bookId))
.build() .build()
.render(RenderingStrategies.MYBATIS3)); .render(RenderingStrategies.MYBATIS3));
if (bookIndexs.size() > 0) { if (bookIndexs.size() > 0) {
return bookIndexs.stream().collect(Collectors.toMap(BookIndex::getIndexNum, Function.identity())); return bookIndexs.stream().collect(Collectors.toMap(BookIndex::getIndexNum, Function.identity()));
} }
return new HashMap<>(0); return new HashMap<>(0);
} }
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@Override @Override
public void updateBookAndIndexAndContent(Book book, List<BookIndex> bookIndexList, List<BookContent> bookContentList, Map<Integer, BookIndex> existBookIndexMap) { public void updateBookAndIndexAndContent(Book book, List<BookIndex> bookIndexList, List<BookContent> bookContentList, Map<Integer, BookIndex> existBookIndexMap) {
for (int i = 0; i < bookIndexList.size(); i++) { for (int i = 0; i < bookIndexList.size(); i++) {
BookIndex bookIndex = bookIndexList.get(i); BookIndex bookIndex = bookIndexList.get(i);
BookContent bookContent = bookContentList.get(i); BookContent bookContent = bookContentList.get(i);
if(!existBookIndexMap.containsKey(bookIndex.getIndexNum())) { if (!existBookIndexMap.containsKey(bookIndex.getIndexNum())) {
//插入 //插入
bookIndexMapper.insertSelective(bookIndex); bookIndexMapper.insertSelective(bookIndex);
bookContentMapper.insertSelective(bookContent); bookContentService.saveBookContent(bookContent,book.getId());
}else{ } else {
//更新 //更新
bookIndexMapper.updateByPrimaryKeySelective(bookIndex); bookIndexMapper.updateByPrimaryKeySelective(bookIndex);
bookContentMapper.update(update(BookContentDynamicSqlSupport.bookContent) bookContentService.updateBookContent(bookContent,book.getId());
.set(BookContentDynamicSqlSupport.content)
.equalTo(bookContent.getContent())
.where(BookContentDynamicSqlSupport.indexId,isEqualTo(bookContent.getIndexId()))
.build()
.render(RenderingStrategies.MYBATIS3));
} }
@ -145,7 +141,7 @@ public class BookServiceImpl implements BookService {
//更新小说主表 //更新小说主表
book.setBookName(null); book.setBookName(null);
book.setAuthorName(null); book.setAuthorName(null);
if(Constants.VISIT_COUNT_DEFAULT.equals(book.getVisitCount())) { if (Constants.VISIT_COUNT_DEFAULT.equals(book.getVisitCount())) {
book.setVisitCount(null); book.setVisitCount(null);
} }
bookMapper.updateByPrimaryKeySelective(book); bookMapper.updateByPrimaryKeySelective(book);
@ -168,7 +164,7 @@ public class BookServiceImpl implements BookService {
.build() .build()
.render(RenderingStrategies.MYBATIS3)); .render(RenderingStrategies.MYBATIS3));
if(books.size()>0){ if (books.size() > 0) {
return books.get(0); return books.get(0);
} }

View File

@ -0,0 +1,44 @@
package com.java2nb.novel.service.impl;
import com.java2nb.novel.entity.BookContent;
import com.java2nb.novel.mapper.BookContentDynamicSqlSupport;
import com.java2nb.novel.mapper.BookContentMapper;
import com.java2nb.novel.service.BookContentService;
import lombok.RequiredArgsConstructor;
import org.mybatis.dynamic.sql.render.RenderingStrategies;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import java.util.List;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
import static org.mybatis.dynamic.sql.SqlBuilder.update;
@Service
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "txt.save", name = "storage", havingValue = "db")
public class DbBookContentServiceImpl implements BookContentService {
private final BookContentMapper bookContentMapper;
@Override
public void saveBookContent(List<BookContent> bookContentList,Long bookId) {
bookContentMapper.insertMultiple(bookContentList);
}
@Override
public void saveBookContent(BookContent bookContent,Long bookId) {
bookContentMapper.insertSelective(bookContent);
}
@Override
public void updateBookContent(BookContent bookContent,Long bookId) {
bookContentMapper.update(update(BookContentDynamicSqlSupport.bookContent)
.set(BookContentDynamicSqlSupport.content)
.equalTo(bookContent.getContent())
.where(BookContentDynamicSqlSupport.indexId,isEqualTo(bookContent.getIndexId()))
.build()
.render(RenderingStrategies.MYBATIS3));
}
}

View File

@ -0,0 +1,36 @@
package com.java2nb.novel.service.impl;
import com.java2nb.novel.core.utils.FileUtil;
import com.java2nb.novel.entity.BookContent;
import com.java2nb.novel.service.BookContentService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "txt.save", name = "storage", havingValue = "file")
public class FileBookContentServiceImpl implements BookContentService {
@Value("${txt.save.path}")
private String fileSavePath;
@Override
public void saveBookContent(List<BookContent> bookContentList,Long bookId) {
bookContentList.forEach(bookContent -> saveBookContent(bookContent,bookId));
}
@Override
public void saveBookContent(BookContent bookContent,Long bookId) {
FileUtil.writeContentToFile(fileSavePath,"/"+bookId+"/"+bookContent.getIndexId()+".txt",bookContent.getContent());
}
@Override
public void updateBookContent(BookContent bookContent,Long bookId) {
FileUtil.writeContentToFile(fileSavePath,"/"+bookId+"/"+bookContent.getIndexId()+".txt",bookContent.getContent());
}
}

View File

@ -5,16 +5,14 @@ import com.java2nb.novel.core.bean.PageBean;
import com.java2nb.novel.core.bean.UserDetails; import com.java2nb.novel.core.bean.UserDetails;
import com.java2nb.novel.core.utils.ThreadLocalUtil; import com.java2nb.novel.core.utils.ThreadLocalUtil;
import com.java2nb.novel.entity.*; import com.java2nb.novel.entity.*;
import com.java2nb.novel.service.AuthorService; import com.java2nb.novel.service.*;
import com.java2nb.novel.service.BookService;
import com.java2nb.novel.service.NewsService;
import com.java2nb.novel.service.UserService;
import com.java2nb.novel.vo.BookCommentVO; import com.java2nb.novel.vo.BookCommentVO;
import com.java2nb.novel.vo.BookSettingVO; import com.java2nb.novel.vo.BookSettingVO;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
@ -36,6 +34,9 @@ import java.util.concurrent.ThreadPoolExecutor;
@Controller @Controller
public class PageController extends BaseController { public class PageController extends BaseController {
@Value("${txt.save.path}")
private String fileSavePath;
private final BookService bookService; private final BookService bookService;
private final NewsService newsService; private final NewsService newsService;
@ -44,6 +45,8 @@ public class PageController extends BaseController {
private final UserService userService; private final UserService userService;
private final BookContentService bookContentService;
private final ThreadPoolExecutor threadPoolExecutor; private final ThreadPoolExecutor threadPoolExecutor;
@ -174,7 +177,7 @@ public class PageController extends BaseController {
*/ */
@SneakyThrows @SneakyThrows
@RequestMapping("/book/{bookId}/{bookIndexId}.html") @RequestMapping("/book/{bookId}/{bookIndexId}.html")
public String indexList(@PathVariable("bookId") Long bookId, @PathVariable("bookIndexId") Long bookIndexId, HttpServletRequest request, Model model) { public String bookContent(@PathVariable("bookId") Long bookId, @PathVariable("bookIndexId") Long bookIndexId, HttpServletRequest request, Model model) {
//加载小说基本信息线程 //加载小说基本信息线程
CompletableFuture<Book> bookCompletableFuture = CompletableFuture.supplyAsync(() -> { CompletableFuture<Book> bookCompletableFuture = CompletableFuture.supplyAsync(() -> {
//查询书籍 //查询书籍
@ -210,7 +213,7 @@ public class PageController extends BaseController {
//加载小说内容信息线程 //加载小说内容信息线程
CompletableFuture<BookContent> bookContentCompletableFuture = CompletableFuture.supplyAsync(() -> { CompletableFuture<BookContent> bookContentCompletableFuture = CompletableFuture.supplyAsync(() -> {
//查询内容 //查询内容
BookContent bookContent = bookService.queryBookContent(bookIndexId); BookContent bookContent = bookContentService.queryBookContent(bookId, bookIndexId);
log.debug("加载小说内容信息线程结束"); log.debug("加载小说内容信息线程结束");
return bookContent; return bookContent;
}, threadPoolExecutor); }, threadPoolExecutor);

View File

@ -0,0 +1,11 @@
package com.java2nb.novel.service;
import com.java2nb.novel.entity.BookContent;
import java.util.List;
public interface BookContentService {
BookContent queryBookContent(Long bookId, Long bookIndexId);
}

View File

@ -0,0 +1,38 @@
package com.java2nb.novel.service.impl;
import com.java2nb.novel.entity.BookContent;
import com.java2nb.novel.mapper.BookContentDynamicSqlSupport;
import com.java2nb.novel.mapper.BookContentMapper;
import com.java2nb.novel.service.BookContentService;
import lombok.RequiredArgsConstructor;
import org.mybatis.dynamic.sql.render.RenderingStrategies;
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import java.util.List;
import static com.java2nb.novel.mapper.BookContentDynamicSqlSupport.bookContent;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
import static org.mybatis.dynamic.sql.SqlBuilder.update;
import static org.mybatis.dynamic.sql.select.SelectDSL.select;
@Service
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "txt.save", name = "storage", havingValue = "db")
public class DbBookContentServiceImpl implements BookContentService {
private final BookContentMapper bookContentMapper;
@Override
public BookContent queryBookContent(Long bookId, Long bookIndexId) {
SelectStatementProvider selectStatement = select(BookContentDynamicSqlSupport.id, BookContentDynamicSqlSupport.content)
.from(bookContent)
.where(BookContentDynamicSqlSupport.indexId, isEqualTo(bookIndexId))
.limit(1)
.build()
.render(RenderingStrategies.MYBATIS3);
return bookContentMapper.selectMany(selectStatement).get(0);
}
}

View File

@ -0,0 +1,39 @@
package com.java2nb.novel.service.impl;
import com.java2nb.novel.core.utils.FileUtil;
import com.java2nb.novel.entity.BookContent;
import com.java2nb.novel.service.BookContentService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.List;
@Service
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "txt.save", name = "storage", havingValue = "file")
public class FileBookContentServiceImpl implements BookContentService {
@Value("${txt.save.path}")
private String fileSavePath;
@SneakyThrows
@Override
public BookContent queryBookContent(Long bookId, Long bookIndexId) {
BufferedReader in = new BufferedReader(new FileReader(fileSavePath + "/" + bookId + "/" + bookIndexId + ".txt"));
StringBuffer sb = new StringBuffer();
String str;
while ((str = in.readLine()) != null) {
sb.append(str);
}
in.close();
return new BookContent() {{
setIndexId(bookIndexId);
setContent(sb.toString());
}};
}
}