当前位置: 首页 > article >正文

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);

    }
}


http://www.kler.cn/news/361355.html

相关文章:

  • ArcGIS002:软件自定义设置
  • MacPro M3无法运行minikube 和 docker
  • 技术面没过,竟然是因为我没用过Pytest框架?
  • [项目详解][boost搜索引擎#1] 概述 | 去标签 | 数据清洗 | scp
  • 量子门电路开销——T门、clifford门、toffoli门、fredkin门
  • springboot 项目集成spring security(极简版)
  • Python 从网页中提取文本内容,进行中文分词和词频统计,并生成词云图进行可视化
  • 计算机网络教学设计稿
  • 自定义中文排序在Java中的实现与注意事项
  • redis的bitmap实现用户签到天数统计
  • 吃透高并发模型与RPC框架,拿下大厂offer!!!
  • VuePress的基本常识
  • HTML基本语法
  • 【电子元件】光通量和色温 (欧司朗LED灯珠 KW3 CGLNM1.TG命名规则)
  • 本币接口服务
  • 对比学习论文随笔 1:正负样本对(Contrastive Learning 基础论文篇)
  • Maven--架构项目管理工具
  • 基于知识图谱的美食推荐系统
  • 《普通逻辑》学习记录——引论
  • 【880线代】线性代数一刷错题整理
  • 裸指针的六个问题
  • 如何提高 YoloDotNet 图像目标检测的准确率?
  • 双碳目标下储能产业新趋势与架构
  • openssl所有版本源码下载链接
  • KafkaTools 3配置 SASL SSL双重认证
  • 基于单片机优先级的信号状态机设计