动态导出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网络请求的数据。


导出样式

相关推荐
ElasticPDF-新国产PDF编辑器21 小时前
Vue use pdf.js and Elasticpdf tutorial
vue.js·pdf
ElasticPDF-新国产PDF编辑器1 天前
Angular 项目 PDF 批注插件库在线版 API 示例教程
前端·pdf·angular.js
夏天想1 天前
vant4+vue3上传一个pdf文件并实现pdf的预览。使用插件pdf.js
开发语言·javascript·pdf·vant
漂洋过海cv1 天前
Word 插入无页眉页码的空白页(即插入奇数页)
word
response_L1 天前
国产系统统信uos和麒麟v10在线打开word给表格赋值
java·c#·word·信创·在线编辑
ElasticPDF-新国产PDF编辑器1 天前
React 项目 PDF 批注插件库在线版 API 示例教程
react.js·pdf·json
hello_simon1 天前
在线小白工具,PPT转PDF支持多种热门工具,支持批量转换,操作简单,高效适合各种需求
pdf·html·powerpoint·excel·pdf转html·excel转pdf格式
ZhangChuChu_92482 天前
Word在生成PDF后,PDF左侧导航书签目录错误显示的解决方法
pdf·word
inxunoffice2 天前
批量将文本文件转换为 Word/PDF/Excel/图片等其它格式
pdf·word·excel
人工智能教学实践2 天前
【爬虫脚本】实现批量pdf文件下载
pdf