redisTemplate;
+
+ @Autowired
+ private BookIndexService bookIndexService;
+
+ @Autowired
+ private BookContentService bookContentService;
+
+
+ private final Pattern PATTERN_BR = Pattern.compile("
", Pattern.CASE_INSENSITIVE);
+ private final Pattern PATTERN_NBSP = Pattern.compile(" ", Pattern.CASE_INSENSITIVE);
+ private final Pattern PATTERN_ANCHOR_OPEN = Pattern.compile("]*>", Pattern.CASE_INSENSITIVE);
+ private final Pattern PATTERN_ANCHOR_CLOSE = Pattern.compile("", Pattern.CASE_INSENSITIVE);
+ private final Pattern PATTERN_DIV_OPEN = Pattern.compile("]*>", Pattern.CASE_INSENSITIVE);
+ private final Pattern PATTERN_DIV_CLOSE = Pattern.compile("
", Pattern.CASE_INSENSITIVE);
+ private final Pattern PATTERN_EMPTY_PARAGRAPH_WITH_LINK = Pattern.compile("]*>[^<]*]*>[^<]*\\s*
", Pattern.CASE_INSENSITIVE);
+ private final Pattern PATTERN_P_OPEN = Pattern.compile("]*>", Pattern.CASE_INSENSITIVE);
+ private final Pattern PATTERN_P_CLOSE = Pattern.compile("
", Pattern.CASE_INSENSITIVE);
+
@GetMapping()
@RequiresPermissions("novel:book:book")
String Book() {
@@ -66,7 +105,7 @@ public class BookController {
@GetMapping("/edit/{id}")
@RequiresPermissions("novel:book:edit")
String edit(@PathVariable("id") Long id, Model model) {
- BookDO book = bookService.get(id);
+ BookDO book = bookService.get(id);
model.addAttribute("book", book);
return "novel/book/edit";
}
@@ -75,7 +114,7 @@ public class BookController {
@GetMapping("/detail/{id}")
@RequiresPermissions("novel:book:detail")
String detail(@PathVariable("id") Long id, Model model) {
- BookDO book = bookService.get(id);
+ BookDO book = bookService.get(id);
model.addAttribute("book", book);
return "novel/book/detail";
}
@@ -87,7 +126,7 @@ public class BookController {
@ResponseBody
@PostMapping("/save")
@RequiresPermissions("novel:book:add")
- public R save( BookDO book) {
+ public R save(BookDO book) {
if (bookService.save(book) > 0) {
return R.ok();
}
@@ -101,8 +140,8 @@ public class BookController {
@ResponseBody
@RequestMapping("/update")
@RequiresPermissions("novel:book:edit")
- public R update( BookDO book) {
- bookService.update(book);
+ public R update(BookDO book) {
+ bookService.update(book);
return R.ok();
}
@@ -113,7 +152,7 @@ public class BookController {
@PostMapping("/remove")
@ResponseBody
@RequiresPermissions("novel:book:remove")
- public R remove( Long id) {
+ public R remove(Long id) {
if (bookService.remove(id) > 0) {
return R.ok();
}
@@ -128,8 +167,83 @@ public class BookController {
@ResponseBody
@RequiresPermissions("novel:book:batchRemove")
public R remove(@RequestParam("ids[]") Long[] ids) {
- bookService.batchRemove(ids);
+ bookService.batchRemove(ids);
return R.ok();
}
+ /**
+ * 小说下载
+ */
+ @RequestMapping(value = "/download")
+ public void download(@RequestParam("bookId") Long bookId, @RequestParam("bookName") String bookName,
+ HttpServletResponse resp) {
+ try {
+ OutputStream out = resp.getOutputStream();
+ Boolean success = redisTemplate
+ .opsForValue()
+ .setIfAbsent(Constant.BOOK_IS_DOWNLOADING_KEY + bookId, "1", 10, TimeUnit.MINUTES);
+ if (Boolean.FALSE.equals(success)) {
+ resp.setContentType("text/html;charset=UTF-8");
+ out.write("该小说正在下载中,请稍后重试!".getBytes(StandardCharsets.UTF_8));
+ out.close();
+ return;
+ }
+ //设置响应头,对文件进行url编码
+ bookName = URLEncoder.encode(bookName, StandardCharsets.UTF_8);
+ //解决手机端不能下载附件的问题
+ resp.setContentType("application/octet-stream");
+ resp.setHeader("Content-Disposition", "attachment;filename=" + bookName + ".txt");
+
+ Map params = new HashMap<>();
+ params.put("bookId", bookId);
+ params.put("sort", "index_num");
+ params.put("order", "asc");
+ params.put("limit", 9999);
+ params.put("offset", 0);
+ List bookIndexBigList = bookIndexService.list(params);
+ if (!bookIndexBigList.isEmpty()) {
+ List> bookIndexSmallList = bookIndexBigList.stream().collect(
+ Collectors.groupingBy(item -> bookIndexBigList.indexOf(item) / 100)).values().stream().toList();
+ for (List bookIndexList : bookIndexSmallList) {
+ // 获取集合中所有的ID
+ List bookIndexIds = bookIndexList.stream().map(BookIndexDO::getId).toList();
+ List bookContentList = bookContentService.listByIndexIds(bookIndexIds);
+ Map bookContentMap = bookContentList.stream()
+ .collect(Collectors.toMap(BookContentDO::getIndexId, BookContentDO::getContent));
+ for (BookIndexDO bookIndex : bookIndexList) {
+ String indexName = bookIndex.getIndexName();
+ if (indexName != null) {
+ String content = bookContentMap.get(bookIndex.getId());
+ out.write(indexName.getBytes(StandardCharsets.UTF_8));
+ out.write("\r\n".getBytes(StandardCharsets.UTF_8));
+ content = PATTERN_BR.matcher(content).replaceAll("\r\n");
+ content = PATTERN_NBSP.matcher(content).replaceAll(" ");
+ content = PATTERN_ANCHOR_OPEN.matcher(content).replaceAll("");
+ content = PATTERN_ANCHOR_CLOSE.matcher(content).replaceAll("");
+ content = PATTERN_DIV_OPEN.matcher(content).replaceAll("");
+ content = PATTERN_DIV_CLOSE.matcher(content).replaceAll("");
+ content = PATTERN_EMPTY_PARAGRAPH_WITH_LINK.matcher(content).replaceAll("");
+ content = PATTERN_P_OPEN.matcher(content).replaceAll("");
+ content = PATTERN_P_CLOSE.matcher(content).replaceAll("\r\n");
+ out.write(content.getBytes(StandardCharsets.UTF_8));
+ out.write("\r\n".getBytes(StandardCharsets.UTF_8));
+ out.write("\r\n".getBytes(StandardCharsets.UTF_8));
+ out.flush();
+ }
+ }
+ }
+
+ }
+
+ out.close();
+
+
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ } finally {
+ redisTemplate.delete(Constant.BOOK_IS_DOWNLOADING_KEY + bookId);
+ }
+
+ }
+
}
diff --git a/novel-admin/src/main/java/com/java2nb/novel/dao/BookContentDao.java b/novel-admin/src/main/java/com/java2nb/novel/dao/BookContentDao.java
index d070322..d520f05 100644
--- a/novel-admin/src/main/java/com/java2nb/novel/dao/BookContentDao.java
+++ b/novel-admin/src/main/java/com/java2nb/novel/dao/BookContentDao.java
@@ -4,6 +4,7 @@ import com.java2nb.common.annotation.SanitizeMap;
import com.java2nb.novel.domain.BookContentDO;
import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
@@ -33,4 +34,6 @@ public interface BookContentDao {
int batchRemove(Long[] ids);
int removeByIndexIds(Long[] indexIds);
+
+ List listByIndexIds(@Param("indexIds") List indexIds);
}
diff --git a/novel-admin/src/main/java/com/java2nb/novel/service/BookContentService.java b/novel-admin/src/main/java/com/java2nb/novel/service/BookContentService.java
index 83e7353..f2a3501 100644
--- a/novel-admin/src/main/java/com/java2nb/novel/service/BookContentService.java
+++ b/novel-admin/src/main/java/com/java2nb/novel/service/BookContentService.java
@@ -27,4 +27,6 @@ public interface BookContentService {
int remove(Long id);
int batchRemove(Long[] ids);
+
+ List listByIndexIds(List indexIds);
}
diff --git a/novel-admin/src/main/java/com/java2nb/novel/service/impl/BookContentServiceImpl.java b/novel-admin/src/main/java/com/java2nb/novel/service/impl/BookContentServiceImpl.java
index 8c6bbd4..0adebae 100644
--- a/novel-admin/src/main/java/com/java2nb/novel/service/impl/BookContentServiceImpl.java
+++ b/novel-admin/src/main/java/com/java2nb/novel/service/impl/BookContentServiceImpl.java
@@ -1,5 +1,6 @@
package com.java2nb.novel.service.impl;
+import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -51,5 +52,10 @@ public class BookContentServiceImpl implements BookContentService {
public int batchRemove(Long[] ids){
return bookContentDao.batchRemove(ids);
}
-
+
+ @Override
+ public List listByIndexIds(List indexIds) {
+ return bookContentDao.listByIndexIds(indexIds);
+ }
+
}
diff --git a/novel-admin/src/main/resources/mybatis/novel/BookContentMapper.xml b/novel-admin/src/main/resources/mybatis/novel/BookContentMapper.xml
index c6de681..7652d25 100644
--- a/novel-admin/src/main/resources/mybatis/novel/BookContentMapper.xml
+++ b/novel-admin/src/main/resources/mybatis/novel/BookContentMapper.xml
@@ -38,6 +38,17 @@