Java实现html填充导出pdf

Java实现html填充导出pdf

1.依赖添加和pom修改

 <!-- Thymeleaf 模板引擎 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- OpenPDF 库 -->
        <dependency>
            <groupId>com.github.librepdf</groupId>
            <artifactId>openpdf</artifactId>
            <version>1.3.29</version>
        </dependency>

        <!-- HTML转PDF工具(flying-saucer) -->
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-core</artifactId>
            <version>9.1.20</version>
        </dependency>

        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf-openpdf</artifactId>
            <version>9.1.20</version>
        </dependency>

为了解决:java.io.IOException: /app/idmp-datam-job.jar!/BOOT-INF/classes!/fonts/SimSun.ttf not found as file or resource.

<resources>
            <resource>
                <directory>src/main/resources</directory>
                <!--开启过滤,用指定的参数替换directory下的文件中的参数-->
                <filtering>true</filtering>
                <excludes>
                    <exclude>fonts/</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>false</filtering>
                <includes>
                    <include>fonts/</include>
                </includes>
            </resource>
        </resources>

2.工具类

操作过程主要出现问题的地方在于字体的问题,字体放在resource/fonts目录下。

第一次运行的时候将文件复制出来然后每次执行就读取外边的。

import com.lowagie.text.pdf.BaseFont;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import java.io.*;
import java.util.List;
import java.util.Map;

/**
 * @author lxz
 * pdf导出
 */
@Slf4j
public class PdfExportUtil {

    /**
     *
     * @param list     需要写入 PDF 的字符串集合
     * @param fileName 生成的 PDF 文件名
     * @throws IOException 如果发生 IO 异常
     */

    public static String exportPdf(List<Map<String,String>> list, String fileName) throws IOException {
        // 创建临时文件
        String path = System.getProperty("user.dir") + File.separator + fileName + ".pdf";
        log.info("【pdf生成】,路径:" + path);
        File tempFile = new File(path);
        if (!tempFile.exists()) {
            log.info("【pdf生成】,文件不存在创建!");
            tempFile.createNewFile();
        }
        // 使用 FileOutputStream 将 PDF 写入到临时文件
        log.info("【pdf生成】,完成html内容生成!");
        // 生成html内容
        String htmlContent = generateHtmlContent(list, fileName);
        // 创建ITextRenderer实例
        ITextRenderer renderer = new ITextRenderer();
        // 设置字体路径,从 resources/fonts 目录加载 SimSun 字体
        ITextFontResolver fontResolver = renderer.getFontResolver();
        Resource resource = new ClassPathResource("fonts/SimSun.ttf");
        File newFontDir = new File(System.getProperty("user.dir") + File.separator + "fonts");
        if (!newFontDir.exists()) {
            newFontDir.mkdirs();
        }
        File newFontFile = new File(newFontDir, "SimSun.ttf");
        if (!newFontFile.exists()) {
            newFontFile.createNewFile();
            // 将 resource 内容写入 newFontFile
            try (InputStream inputStream = resource.getInputStream();
                 OutputStream outputStream = new FileOutputStream(newFontFile)) {
                // 使用缓冲区进行复制
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }
            log.info("【pdf下载】,字体文件已成功复制到" + newFontFile.getAbsolutePath());
        } else {
            log.info("【pdf下载】,字体已存在:" + newFontFile.getAbsolutePath());
        }
        fontResolver.addFont(newFontFile.getPath(), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        log.info("【pdf生成】,加载字体成功!");
        // 设置HTML内容
        renderer.setDocumentFromString(htmlContent);
        log.info("【pdf生成】,生成内容!");
        renderer.layout();
        // 输出PDF到响应输出流
        try (OutputStream outputStream = new FileOutputStream(tempFile)) {
            renderer.createPDF(outputStream);
            outputStream.flush();
            log.info("【pdf生成】,生成完成!");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return path;
    }


    /**
     * 生成HTML内容
     * @return 渲染后的HTML字符串
     */
    public static String generateHtmlContent(List<Map<String,String>> list, String fileName) {
        //thymeleaf构造模板引擎;给html文件赋值
        ClassLoaderTemplateResolver resolver = new ClassLoaderTemplateResolver();
        //默认是找classpath路径下的资源
        resolver.setPrefix("templates/");
        //模板文件后缀
        resolver.setSuffix(".html");
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(resolver);
        log.info("【pdf生成】,填充html内容!");
        Context context = new Context();
        context.setVariable("title", fileName);
        context.setVariable("list", list);
        return templateEngine.process("pdf_template", context);
    }
}

字体文件:

3.模板文件

resource/templates目录下。

主要靠thymeleaf来实现的。

内容如下:

<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title th:text="${title}"></title>
    <style>
        body {
            font-family: 'SimSun', sans-serif;
        }
    </style>
</head>
<body>
<div data-th-each="item:${list}">
    <div th:text="${item.content}" th:style="${item.style}"></div>
</div>
</body>
</html>

4.测试方法

@RestController
@RequestMapping("/api/pdf")
public class PdfController {

    @GetMapping("/test")
    @TinyResponse
    public void downloadPdf() throws Exception {
        List<Map<String,String>> list = new ArrayList<>();
        for (int i =0; i< 100; i++) {
            Map<String,String> map = new HashMap<>();
            map.put("content", "测试内容生成111111");
            map.put("style", "color:red;font-size: 12px;");
            list.add(map);
        }
        String fileName = "测试pdf名称";
        PdfExportUtil.exportPdf(list, fileName);

    }
}
相关推荐
钱多多_qdd7 分钟前
spring cache源码解析(四)——从@EnableCaching开始来阅读源码
java·spring boot·spring
waicsdn_haha9 分钟前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk
_WndProc11 分钟前
C++ 日志输出
开发语言·c++·算法
Q_192849990619 分钟前
基于Spring Boot的摄影器材租赁回收系统
java·spring boot·后端
qq_4335545420 分钟前
C++ 面向对象编程:+号运算符重载,左移运算符重载
开发语言·c++
Code_流苏22 分钟前
VSCode搭建Java开发环境 2024保姆级安装教程(Java环境搭建+VSCode安装+运行测试+背景图设置)
java·ide·vscode·搭建·java开发环境
数据小爬虫@39 分钟前
如何高效利用Python爬虫按关键字搜索苏宁商品
开发语言·爬虫·python
ZJ_.41 分钟前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
Narutolxy1 小时前
深入探讨 Go 中的高级表单验证与翻译:Gin 与 Validator 的实践之道20241223
开发语言·golang·gin
Hello.Reader1 小时前
全面解析 Golang Gin 框架
开发语言·golang·gin