动态导出word文件支持转pdf

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、功能说明

复制代码
将要导出的文件已动态方式进行下载

二、使用步骤

1.controller

代码如下(示例):

c 复制代码
 @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

代码如下(示例):

c 复制代码
 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("&nbsp;", "&#160;");
            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网络请求的数据。


导出样式

相关推荐
敲代码的小吉米7 小时前
前端上传el-upload、原生input本地文件pdf格式(纯前端预览本地文件不走后端接口)
前端·javascript·pdf·状态模式
东方巴黎~Sunsiny11 小时前
EasyExcel导出excel再转PDF转图片详解
pdf·excel
wqqqianqian11 小时前
国产linux系统(银河麒麟,统信uos)使用 PageOffice自定义Word模版中的数据区域
linux·word·自定义·pageoffice·数据区域
aklry14 小时前
uniapp实现在线pdf预览以及下载
前端·pdf·uni-app
繁依Fanyi14 小时前
我的 PDF 工具箱:CodeBuddy 打造 PDFMagician 的全过程记录
java·pdf·uni-app·生活·harmonyos·codebuddy首席试玩官
DevOpenClub20 小时前
PPT 转高精度 PDF API 接口
pdf·powerpoint
想太多会累i1 天前
Spring Boot 使用Itext绘制并导出PDF
spring boot·pdf
zixingcai1 天前
Adobe Acrobat pro在一份PDF中插入空白页
pdf·adobe acrobat reader
課代表1 天前
AcroForm JavaScript Promise 对象应用示例: 异步加载PDF文件
开发语言·javascript·pdf·promise·对象
charlie1145141911 天前
基于Qt6 + MuPDF在 Arm IMX6ULL运行的PDF浏览器——MuPDF Adapter文档
arm开发·qt·学习·pdf·教程·设计·qt6