提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、功能说明
- 二、使用步骤
- 1.controller
- 2.工具类 DocumentUtil
- 导出样式
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、功能说明
将要导出的文件已动态方式进行下载
二、使用步骤
1.controller
代码如下(示例):
@ApiOperation("导出维权word模板")@GetMapping("/export/{id}")public ResponseEntity<byte[]> exportWord(@PathVariable("id") Long id) throws IOException {// 获取 SupervisionDocument 对象SupervisionDocument supervisionDocument = service.getById(id);// 创建并填充数据模型HashMap<String, Object> dataMap = new HashMap<>();//将base64的内容进行解码String s = new String(Base64.getDecoder().decode(supervisionDocument.getSupervisionOrderText()));dataMap.put("content", s);//编号判断如果获取为空则默认空格dataMap.put("number", supervisionDocument.getSupervisionOrderNumber());//整改时限dataMap.put("time", new SimpleDateFormat("yyyy年MM月dd日").format(supervisionDocument.getRectificationDeadline()));//录入时间dataMap.put("entryTime", new SimpleDateFormat("yyyy年MM月dd日").format(supervisionDocument.getCreatedAt()));//录入单位dataMap.put("entryUnit", supervisionDocument.getEntryUnit());//被堵办单位dataMap.put("supervisedUnit", supervisionDocument.getSupervisedUnit());//获取附件dataMap.put("attachment", splitUrl(supervisionDocument.getAttachments()));if (supervisionDocument.getDocumentType().equals("1")) {// 生成文档的字节流ByteArrayOutputStream outputStream = DocumentUtil.generateDocAsStream("word/提示函.docx",dataMap);// 设置文件下载的文件名String fileName = "提示函_" + id + ".docx";// 设置响应头确保文件下载HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);headers.setContentDispositionFormData("attachment", new String(fileName.getBytes("UTF-8"), "ISO-8859-1"));// 返回文件流内容作为响应体return new ResponseEntity<>(outputStream.toByteArray(), headers, HttpStatus.OK);}
2.工具类 DocumentUtil
代码如下(示例):
package com.ruoyi.common.core.utils;import com.deepoove.poi.XWPFTemplate;
import com.openhtmltopdf.pdfboxout.PdfRendererBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;/*** 文档处理工具类。* <p>* 提供生成Word和PDF文档的方法。* </p>* @author Administrator*/
public class DocumentUtil {private static final Logger logger = LoggerFactory.getLogger(DocumentUtil.class);/*** 生成Word文档** @param templatePath 模板文件路径* @param outputPath 输出文件路径* @param data 数据模型* @throws IOException 如果文档生成失败*/public static void generateDoc(String templatePath, String outputPath, Map<String, Object> data) throws IOException {logger.info("开始生成Word文档,模板路径:{},输出路径:{}", templatePath, outputPath);if (Files.exists(Paths.get(outputPath))) {throw new IOException("文件已存在:" + outputPath);}XWPFTemplate template = XWPFTemplate.compile(templatePath);try {template.render(data);try (FileOutputStream out = new FileOutputStream(outputPath)) {template.write(out);}} catch (Exception e) {logger.error("生成Word文档时发生错误", e);throw new IOException("生成Word文档时发生错误:" + e.getMessage(), e);} finally {template.close();}logger.info("Word文档生成成功,输出路径:{}", outputPath);}/*** 生成Word文档并返回文件流** @param templatePath 模板文件路径* @param data 数据模型* @return 文件流* @throws IOException 如果文档生成失败*/public static ByteArrayOutputStream generateDocAsStream(String templatePath, Map<String, Object> data) throws IOException {// 从 classpath 中读取模板文件流try (InputStream templateStream = DocumentUtil.class.getClassLoader().getResourceAsStream(templatePath)) {if (templateStream == null) {throw new IOException("模板文件未找到:" + templatePath);}// 创建 XWPFTemplate 实例并渲染数据XWPFTemplate template = XWPFTemplate.compile(templateStream);ByteArrayOutputStream outputStream = new ByteArrayOutputStream();try {template.render(data); // 将数据渲染到模板template.write(outputStream); // 将模板内容写入输出流} catch (Exception e) {logger.error("生成Word文档时发生错误", e);throw new IOException("生成Word文档时发生错误:" + e.getMessage(), e);} finally {template.close();}logger.info("Word文档生成成功");return outputStream;}}/*** 生成PDF文件** @param htmlContent HTML内容* @param outputPath 输出文件路径* @throws IOException 如果PDF生成失败*/public static void generatePdf(String htmlContent, String outputPath) throws IOException {logger.info("开始生成PDF文件,输出路径:{}", outputPath);if (Files.exists(Paths.get(outputPath))) {throw new IOException("文件已存在:" + outputPath);}try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {PdfRendererBuilder builder = new PdfRendererBuilder();builder.useFastMode();builder.withHtmlContent(htmlContent, null);builder.toStream(os);builder.run();try (FileOutputStream fos = new FileOutputStream(outputPath)) {fos.write(os.toByteArray());}} catch (Exception e) {logger.error("生成PDF文件时发生错误", e);throw new IOException("生成PDF文件时发生错误:" + e.getMessage(), e);}logger.info("PDF文件生成成功,输出路径:{}", outputPath);}/*** 生成PDF文件并返回文件流** @param htmlContent HTML内容* @return 文件流* @throws IOException 如果PDF生成失败*//*** 生成PDF文件并返回文件流** @param htmlContent HTML内容* @return 文件流* @throws IOException 如果PDF生成失败*/public static ByteArrayOutputStream generatePdfAsStream(String htmlContent) throws IOException {logger.info("开始生成PDF文件");ByteArrayOutputStream outputStream = new ByteArrayOutputStream();try {PdfRendererBuilder builder = new PdfRendererBuilder();builder.useFastMode();// 设置中文字体路径String fontPath = DocumentUtil.class.getClassLoader().getResource("SimSun.ttf").toExternalForm();// 嵌入中文字体builder.useFont(() -> DocumentUtil.class.getClassLoader().getResourceAsStream("SimSun.ttf"), "SimSun");// 在HTML中使用该字体htmlContent = htmlContent.replace("<head>", "<head>\n<style>@font-face { font-family: 'SimSun'; src: url('" + fontPath + "'); }</style>");htmlContent = htmlContent.replace(" ", " ");htmlContent = htmlContent.replace("“", "“");htmlContent = htmlContent.replace("”", "”");// 去除html body 里的字体样式 只去除body里的htmlContent = htmlContent.replace("<body>", "<body style=\"font-family: 'SimSun', Arial, sans-serif;\">");htmlContent = cleanHtmlBodyFonts(htmlContent);builder.withHtmlContent(htmlContent, null);builder.toStream(outputStream);builder.run();} catch (Exception e) {logger.error("生成PDF文件时发生错误", e);throw new IOException("生成PDF文件时发生错误:" + e.getMessage(), e);}logger.info("PDF文件生成成功");return outputStream;}/*** 生成包含复杂内容的PDF文件** @param outputPath 输出文件路径* @throws IOException 如果PDF生成失败*/public static void generateComplexPdf(String outputPath) throws IOException {String htmlContent = "<!DOCTYPE html>\n" +"<html lang=\"en\">\n" +"<head>\n" +" <meta charset=\"UTF-8\" />\n" +" <style>\n" + " body {\n" +" font-family: 'SimSun', Arial, sans-serif;\n" +" }" +" h1 {\n" +" color: #333;\n" +" }\n" +" p {\n" +" font-size: 14px;\n" +" line-height: 1.5;\n" +" }\n" +" table {\n" +" width: 100%;\n" +" border-collapse: collapse;\n" +" }\n" +" table, th, td {\n" +" border: 1px solid black;\n" +" }\n" +" th, td {\n" +" padding: 8px;\n" +" text-align: left;\n" +" }\n" +" img {\n" +" width: 100px;\n" +" height: auto;\n" +" }\n" +" </style>\n" +" <title>Complex PDF Example</title>\n" +"</head>\n" +"<body>\n" +" <h1>PDF生成示例</h1>\n" +" <p>这是一个包含不同内容的PDF示例。</p>\n" +" <h2>表格</h>\n" +" <table>\n" +" <tr>\n" +" <th>名称</th>\n" +" <th>年龄</th>\n" +" <th>城市</th>\n" +" </tr>\n" +" <tr>\n" +" <td>张三</td>\n" +" <td>30</td>\n" +" <td>北京</td>\n" +" </tr>\n" +" <tr>\n" +" <td>李四</td>\n" +" <td>25</td>\n" +" <td>上海</td>\n" +" </tr>\n" +" </table>\n" +" <h2>图像</h2>\n" +" <img src=\"https://via.placeholder.com/100\" alt=\"示例图像\" />\n" +"</body>\n" +"</html>";generatePdf(htmlContent, outputPath);}/*** 生成包含复杂内容的PDF文件并返回文件流** @return 文件流* @throws IOException 如果PDF生成失败*/public static ByteArrayOutputStream generateComplexPdfAsStream() throws IOException {String htmlContent = "<!DOCTYPE html>\n" +"<html lang=\"en\">\n" +"<head>\n" +" <meta charset=\"UTF-8\" />\n" +" <style>\n" + " body {\n" +" font-family: 'SimSun', Arial, sans-serif;\n" +" }" +" h1 {\n" +" color: #333;\n" +" }\n" +" p {\n" +" font-size: 14px;\n" +" line-height: 1.5;\n" +" }\n" +" table {\n" +" width: 100%;\n" +" border-collapse: collapse;\n" +" }\n" +" table, th, td {\n" +" border: 1px solid black;\n" +" }\n" +" th, td {\n" +" padding: 8px;\n" +" text-align: left;\n" +" }\n" +" img {\n" +" width: 100px;\n" +" height: auto;\n" +" }\n" +" </style>\n" +" <title>Complex PDF Example</title>\n" +"</head>\n" +"<body>\n" +" <h1>PDF生成示例</h1>\n" +" <p>这是一个包含不同内容的PDF示例。</p>\n" +" <h2>表格</h2>\n" +" <table>\n" +" <tr>\n" +" <th>名称</th>\n" +" <th>年龄</th>\n" +" <th>城市</th>\n" +" </tr>\n" +" <tr>\n" +" <td>张三</td>\n" +" <td>30</td>\n" +" <td>北京</td>\n" +" </tr>\n" +" <tr>\n" +" <td>李四</td>\n" +" <td>25</td>\n" +" <td>上海</td>\n" +" </tr>\n" +" </table>\n" +" <h2>图像</h2>\n" +" <img src=\"https://via.placeholder.com/100\" alt=\"示例图像\" />\n" +"</body>\n" +"</html>";return generatePdfAsStream(htmlContent);}public static String cleanHtmlBodyFonts(String htmlContent) {// 清除内联样式中的字体相关属性String cleaned = htmlContent.replaceAll("font-family:\\s*[^;\"']+;?", "" // 清除 font-family).replaceAll("style=\"\\s*\"", "" // 清除空的style属性).replaceAll("<body[^>]*>", "<body style=\"font-family: 'SimSun', Arial, sans-serif;\">" // 替换body标签);// 清除仿宋_GB2312等特定字体类cleaned = cleaned.replaceAll("font-family:\\s*[仿宋楷体]+((_GB2312)|(_GBK))?[^;\"']*;?", "");return cleaned;}
}
该处使用的url网络请求的数据。