From 6ef573c77708b83262c80e71eb63363eff709720 Mon Sep 17 00:00:00 2001
From: AntonyCheng <1911261716@qq.com>
Date: Tue, 9 Apr 2024 23:18:17 +0800
Subject: [PATCH] =?UTF-8?q?SpringBoot=E5=88=9D=E5=A7=8B=E5=8C=96=E6=A8=A1?=
=?UTF-8?q?=E6=9D=BFv2.1.4=20=E8=AE=BE=E8=AE=A1Apache=20POI=E6=93=8D?=
=?UTF-8?q?=E4=BD=9CWord=E6=A8=A1=E5=9D=97=E5=8F=8A=E5=85=B6=E9=85=8D?=
=?UTF-8?q?=E5=A5=97=E5=B7=A5=E5=85=B7=E7=B1=BB=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 19 ++---
.../controller/AuthController.java | 10 +++
.../utils/document/excel/ExcelUtils.java | 21 +++---
.../utils/document/word/WordUtils.java | 74 +++++++++++++++++++
src/main/resources/templates/word/README.md | 1 +
5 files changed, 102 insertions(+), 23 deletions(-)
create mode 100644 src/main/resources/templates/word/README.md
diff --git a/pom.xml b/pom.xml
index 2e7a9227..31d6d9c0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -93,6 +93,7 @@
8.5.9
5.2.5
+ 1.12.2
3.3.4
8.0.3
@@ -393,6 +394,11 @@
poi-ooxml
${poi.version}
+
+ com.deepoove
+ poi-tl
+ ${poi.tl.version}
+
com.alibaba
easyexcel
@@ -513,23 +519,10 @@
src/main/resources
-
- false
src/main/webapp/
-
- src/main/resources
-
-
- application*
- bootstrap*
- logback*
-
-
- true
-
diff --git a/src/main/java/top/sharehome/springbootinittemplate/controller/AuthController.java b/src/main/java/top/sharehome/springbootinittemplate/controller/AuthController.java
index 4d76f501..24b0bd82 100644
--- a/src/main/java/top/sharehome/springbootinittemplate/controller/AuthController.java
+++ b/src/main/java/top/sharehome/springbootinittemplate/controller/AuthController.java
@@ -1,6 +1,7 @@
package top.sharehome.springbootinittemplate.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
+import cn.dev33.satoken.annotation.SaIgnore;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -13,9 +14,11 @@
import top.sharehome.springbootinittemplate.model.dto.auth.AuthRegisterDto;
import top.sharehome.springbootinittemplate.model.vo.auth.AuthLoginVo;
import top.sharehome.springbootinittemplate.service.AuthService;
+import top.sharehome.springbootinittemplate.utils.document.excel.ExcelUtils;
import top.sharehome.springbootinittemplate.utils.satoken.LoginUtils;
import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
import java.util.Map;
/**
@@ -31,6 +34,13 @@ public class AuthController {
@Resource
private AuthService authService;
+ @GetMapping("/test")
+ @SaIgnore
+ public R test(HttpServletResponse response) {
+ ExcelUtils.exportTemplateHttpServletResponse("test", response);
+ return R.empty();
+ }
+
/**
* 注册
* todo 模板默认不使用该接口,但保留该接口,因为该模板中真实增加用户的接口应该是管理员增加用户
diff --git a/src/main/java/top/sharehome/springbootinittemplate/utils/document/excel/ExcelUtils.java b/src/main/java/top/sharehome/springbootinittemplate/utils/document/excel/ExcelUtils.java
index 61066c13..55b15a5a 100644
--- a/src/main/java/top/sharehome/springbootinittemplate/utils/document/excel/ExcelUtils.java
+++ b/src/main/java/top/sharehome/springbootinittemplate/utils/document/excel/ExcelUtils.java
@@ -3,9 +3,12 @@
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
+import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ResourceUtils;
import top.sharehome.springbootinittemplate.common.base.ReturnCode;
import top.sharehome.springbootinittemplate.config.easyexcel.convert.date.ExcelDateConverter;
@@ -712,29 +715,27 @@ public static void exportTemplateHttpServletResponse(String templateName, Cl
}
/**
- * 导出Excel模板目录下的模板文件,同时关闭请求响应流并提交响应,模板目录一定是resources文件夹下templates/excel目录
+ * 导出Excel.xlsx模板目录下的模板文件,同时关闭请求响应流并提交响应,模板目录一定是resources文件夹下templates/excel目录
* 在Controller中建议直接返回void,如果想要统一返回响应类型R,可以使用R.empty()方法。
*
* @param templateName resource模板名称(不带后缀)
* @param response 请求响应流
- * @param 泛型T
*/
- public static void exportTemplateHttpServletResponse(String templateName, HttpServletResponse response) {
+ public static void exportTemplateHttpServletResponse(String templateName, HttpServletResponse response) {
try {
- File file = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX + "templates/excel/" + templateName + ExcelTypeEnum.XLSX.getValue());
- if (!file.isFile()) {
- throw new FileNotFoundException();
+ ClassPathResource classPathResource = new ClassPathResource("templates/excel/" + templateName + ExcelTypeEnum.XLSX.getValue());
+ if (!classPathResource.exists()) {
+ throw new CustomizeExcelException(ReturnCode.EXCEL_FILE_ERROR, "模板文件[" + templateName + ".xlsx]未找到");
}
+ InputStream inputStream = classPathResource.getInputStream();
handleResponse(templateName, response);
- FileInputStream fileInputStream = new FileInputStream(file);
int len = 0;
byte[] buffer = new byte[1024];
ServletOutputStream outputStream = response.getOutputStream();
- while ((len = fileInputStream.read(buffer)) > 0) {
+ while ((len = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, len);
}
- fileInputStream.close();
- outputStream.flush();
+ inputStream.close();
outputStream.close();
} catch (FileNotFoundException e) {
throw new CustomizeExcelException(ReturnCode.EXCEL_FILE_ERROR, "模板文件[" + templateName + ".xlsx]未找到");
diff --git a/src/main/java/top/sharehome/springbootinittemplate/utils/document/word/WordUtils.java b/src/main/java/top/sharehome/springbootinittemplate/utils/document/word/WordUtils.java
index 63998ca7..ce17e9bf 100644
--- a/src/main/java/top/sharehome/springbootinittemplate/utils/document/word/WordUtils.java
+++ b/src/main/java/top/sharehome/springbootinittemplate/utils/document/word/WordUtils.java
@@ -2,6 +2,7 @@
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
+import com.deepoove.poi.XWPFTemplate;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Builder;
@@ -16,7 +17,9 @@
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
+import org.springframework.core.io.ClassPathResource;
import top.sharehome.springbootinittemplate.common.base.ReturnCode;
+import top.sharehome.springbootinittemplate.exception.customize.CustomizeExcelException;
import top.sharehome.springbootinittemplate.exception.customize.CustomizeReturnException;
import javax.imageio.ImageIO;
@@ -38,6 +41,77 @@
@Slf4j
public class WordUtils {
+ /**
+ * 输出Word模板内部类
+ * 该导出模板是基于POI-TL框架的封装,该框架主要以"{{XXX}}"型标签为内容插入点,具体用法查看https://deepoove.com/poi-tl
+ */
+ public static class Template {
+
+ /**
+ * 导出Word.docx模板目录下的模板文件到响应流,模板目录一定是resources文件夹下templates/word目录
+ *
+ * @param templateName 模板名称
+ * @param tagMap 标签Map
+ * @param filename 导出文件名称
+ * @param response 响应流
+ */
+ public static void export(String templateName, Map tagMap, String filename, HttpServletResponse response) {
+ try {
+ handleWordResponse(filename, response);
+ ServletOutputStream outputStream = response.getOutputStream();
+ export(templateName, tagMap, outputStream);
+ } catch (IOException e) {
+ throw new CustomizeReturnException(ReturnCode.WORD_FILE_ERROR);
+ }
+ }
+
+ /**
+ * 导出Word.docx模板目录下的模板文件到输出流,模板目录一定是resources文件夹下templates/word目录
+ *
+ * @param templateName 模板名称
+ * @param tagMap 标签Map
+ * @param outputStream 输出流
+ */
+ public static void export(String templateName, Map tagMap, OutputStream outputStream) {
+ try {
+ ClassPathResource classPathResource = new ClassPathResource("templates/word/" + templateName + ".docx");
+ if (!classPathResource.exists()) {
+ throw new CustomizeExcelException(ReturnCode.EXCEL_FILE_ERROR, "模板文件[" + templateName + ".docx]未找到");
+ }
+ InputStream inputStream = classPathResource.getInputStream();
+ XWPFTemplate template = XWPFTemplate.compile(inputStream).render(tagMap);
+ template.writeAndClose(outputStream);
+ inputStream.close();
+ } catch (IOException e) {
+ throw new CustomizeReturnException(ReturnCode.WORD_FILE_ERROR);
+ }
+ }
+
+ /**
+ * 处理ContentType是Word格式的响应
+ *
+ * @param fileName 文件名
+ * @param response 响应
+ */
+ private static void handleWordResponse(String fileName, HttpServletResponse response) throws UnsupportedEncodingException {
+ String realName = null;
+ if (StringUtils.isBlank(fileName)) {
+ realName = UUID.randomUUID().toString().replace("-", "") + ".docx";
+ } else {
+ realName = UUID.randomUUID().toString().replace("-", "") + "_" + fileName + ".docx";
+ }
+ String encodeName = URLEncoder
+ .encode(realName, StandardCharsets.UTF_8.toString())
+ .replaceAll("\\+", "%20");
+ String contentDispositionValue = "attachment; filename=" + encodeName + ";filename*=utf-8''" + encodeName;
+ response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
+ response.setHeader("Content-disposition", contentDispositionValue);
+ response.setHeader("download-filename", encodeName);
+ response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=UTF-8");
+ }
+
+ }
+
/**
* 写入Word数据内部类
*/
diff --git a/src/main/resources/templates/word/README.md b/src/main/resources/templates/word/README.md
new file mode 100644
index 00000000..037a2858
--- /dev/null
+++ b/src/main/resources/templates/word/README.md
@@ -0,0 +1 @@
+### 存放Word模板的目录
\ No newline at end of file