动态导出word文件支持转pdf

news2024/12/18 6:31:07

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

文章目录

  • 前言
  • 一、功能说明
  • 二、使用步骤
    • 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("&nbsp;", "&#160;");
            htmlContent = htmlContent.replace("&ldquo;", "“");
            htmlContent = htmlContent.replace("&rdquo;", "”");
            // 去除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网络请求的数据。


导出样式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2261447.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

那些不属性的C语言关键字-const

大家都知道const修饰的变量是不可变的&#xff0c;但是到底是怎么实现的那&#xff0c;有方法修改只读变量的值吗&#xff0c;今天我们结合实验代码&#xff0c;分析下const关键字的实现原理 const变量 1.const修饰局部变量 int main(){const int abc 123;printf("%d\…

【Java 数据结构】List -> 给我一个接口!!!

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 目录 1. 什么是 List 2. List 常用的方法 3. List 的使用 1. 什么是 List 其实 List 是一个接口&#xff0c;它继承了 Collection 接口 下列为 List 接口中的各种…

【5G】5G的主要架构选项

最初&#xff0c;在3GPP讨论中考虑了所有可能的聚合和核心网络组合&#xff0c;共有八个架构选项。以下重点介绍option2、3、4和7。 1. 独立组网 (Standalone, SA) 架构选项 2 &#xff1a;Standalone architecture with 5G-core 特点&#xff1a; 5G核心网&#xff08;5GC, …

Ajax简单理解

Ajax 1 什么是ajax AJAXAsynchronous JavaScript and XML (异步的JavaScript和XML)AJAX不是新的编程语言&#xff0c;二十一种使用现有标准的新方法 AJAX 最大的优点是在不重新加载整个页面的情况下&#xff0c;可以与服务器交换数据并更新部分网页内容。 AJAX 不需要任何浏…

【GESP】C++二级考试大纲知识点梳理, (2)计算机网络的基本概念及分类

GESP C二级官方考试大纲中&#xff0c;共有9条考点&#xff0c;本文针对C&#xff08;2&#xff09;号知识点进行总结梳理。 &#xff08;2&#xff09;了解计算机网络的概念&#xff0c;了解计算机网络的分类&#xff08;广域网&#xff08;WAN&#xff09;、城域网&#xff0…

相机与NAS的奇妙组合,如何使用相机拍照自动上传或备份到NAS

相机与NAS的奇妙组合&#xff0c;如何使用相机拍照自动上传或备份到NAS 哈喽小伙伴们好&#xff0c;我是Stark-C~ 对于喜欢使用专业器材拍照摄影的小伙伴来说&#xff0c;想要将相机存储卡中的照片或视频导出到电脑上&#xff0c;要么是使用数据线直接和相机连接&#xff0c;…

window下的qt5.14.2配置vs2022

这里做一个笔记&#xff0c;已知qt5.14.2和vs2022不兼容&#xff0c;无法自动扫描到vs的编译器。但由于团队协作原因&#xff0c;必须使用qt5.14.2&#xff0c;并且第三方库又依赖vs2022。其实qt5.15.2是支持vs2022的&#xff0c;如果能够用qt5.15.2&#xff0c;还是建议使用qt…

QT从入门到精通(一)——Qlabel介绍与使用

1. QT介绍——代码测试 Qt 是一个跨平台的应用程序开发框架&#xff0c;广泛用于开发图形用户界面&#xff08;GUI&#xff09;应用程序&#xff0c;也支持非图形应用程序的开发。Qt 提供了一套工具和库&#xff0c;使得开发者能够高效地构建高性能、可移植的应用程序。以下是…

【协作笔记Trilium Notes Docker部署】开源协作笔记Trilium Notes本地Docker部署远程协作

文章目录 前言1. 安装docker与docker-compose2. 启动容器运行镜像3. 本地访问测试4.安装内网穿透5. 创建公网地址6. 创建固定公网地址 前言 今天分享一款在G站获得了26K的强大的开源在线协作笔记软件&#xff0c;Trilium Notes的中文版如何在Linux环境使用docker本地部署&…

app的测试范围以及web和app的测试区别

目录 图1.App的测试范围1.1功能测试1.2专项测试1.3性能测试 2.Web和App的测试区别2.1相同点2.2不同点 &#x1f44d; 点赞&#xff0c;你的认可是我创作的动力&#xff01; ⭐️ 收藏&#xff0c;你的青睐是我努力的方向&#xff01; ✏️ 评论&#xff0c;你的意见是我进步的…

数据分析实战—鸢尾花数据分类

1.实战内容 (1) 加载鸢尾花数据集(iris.txt)并存到iris_df中,使用seaborn.lmplot寻找class&#xff08;种类&#xff09;项中的异常值&#xff0c;其他异常值也同时处理 。 import pandas as pd from sklearn.datasets import load_iris pd.set_option(display.max_columns, N…

docker 拉取镜像 | 创建容器 | 容器运行

拉取镜像 拉取镜像的命令&#xff1a;docker pull name &#xff08;name换为你要拉取的镜像名&#xff09; docker pull docker.1panel.live/hispark/qiankunbp:1.0.0 docker.1panel.live/hispark/qiankunbp:1.0.0为镜像名 拉取海思的镜像&#xff1a;&#xff08;如果之前拉…

添加标签(vue3)

点击添加按钮&#xff1a; 最多添加5个 注意&#xff1a; 不只可以el-form 进行校验&#xff0c;也可以对单个el-form-item 进行校验 vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法-CSDN博客 el-form 里边有el-form-item &#xff0c;el-fo…

Dash for Mac 代码API文档管理软件安装

Mac分享吧 文章目录 Dash for Mac 代码API文档管理软件 效果图展示一、Dash 代码API文档管理软件 Mac电脑版——v7.3.31️⃣&#xff1a;下载软件2️⃣&#xff1a;安装软件2.1 左侧安装包拖入右侧文件夹中&#xff0c;等待安装完成&#xff0c;运行软件2.2 打开软件&#xff…

Unity添加newtonsoft-json

package name "com.unity.nuget.newtonsoft-json": "3.2.1",打开包管理器 输入包名称和版本 点击添加

分布式全文检索引擎ElasticSearch-数据的写入存储底层原理

一、数据写入的核心流程 当向 ES 索引写入数据时&#xff0c;整体流程如下&#xff1a; 1、客户端发送写入请求 客户端向 ES 集群的任意节点&#xff08;称为协调节点&#xff0c;Coordinating Node&#xff09;发送一个写入请求&#xff0c;比如 index&#xff08;插入或更…

TensorRT C++ API模型加速 —— TensorRT配置、模型转换、CUDA C++加速、TensorRT C++ 加速

文章目录 前言&#xff1a;TensorRT简介0.1、TensorRT算法流程0.2、TensorRT主要优化技术 一、TensorRT配置1.1、TensorRT环境配置1.1.1、CUDA安装1.1.2、TensorRT下载1.1.3、TensorRT CUDA配置1.1.4、TensorRT配置1.1.4.1、TensorRT python配置1.1.4.2、TensorRT C配置&#x…

RPC 服务与 gRPC 的入门案例

RPC 协议 RPC&#xff08;Remote Procedure Call Protocol&#xff09;即远程过程调用协议&#xff0c;它是一种通过网络从远程计算机程序上请求服务的协议&#xff0c;允许一个计算机程序可以像调用本地服务一样调用远程服务 。 RPC的主要作用是不同的服务间方法调用就像本地…

基于Spring Boot的体育商品推荐系统

一、系统背景与目的 随着电子商务的快速发展和人们健康意识的提高&#xff0c;体育商品市场呈现出蓬勃发展的态势。然而&#xff0c;传统的体育商品销售方式存在商品种类繁多、用户选择困难、个性化需求无法满足等问题。为了解决这些问题&#xff0c;基于Spring Boot的体育商品…

在 DDD 中优雅的发送 Kafka 消息

前言 1:host 映射 下载 SwitchHost 配置一个映射地址。点击 添加一个本地环境&#xff0c;之后配置你的 IP kafka 这样就能找这个地址了。IP 为你本地的IP&#xff0c;如果是云服务器就是公网IP地址 使用docker-compose.yml进行一键部署安装 version: 3.0 # docker-compose …