Java实现html填充导出pdf

devtools/2024/10/23 8:11:33/

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 内容写入 newFontFiletry (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")@TinyResponsepublic 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.ppmy.cn/devtools/128111.html

相关文章

线性可分支持向量机的原理推导 9-32线性分类超平面的位置 公式解析

本文是将文章《线性可分支持向量机的原理推导》中的公式单独拿出来做一个详细的解析&#xff0c;便于初学者更好的理解。 公式 9-32 是线性可分支持向量机&#xff08;SVM&#xff09;中的一个关键公式&#xff0c;用于表达线性分类超平面的位置。通过这个公式&#xff0c;我们…

深度学习:Yolo系列 V1和V2的对比

YOLO V1和V2的对比&#xff1a; BatchNorm V2版本舍弃dropout&#xff0c;卷积后全部加入batch normalization网络的每一层的输入都做了归一化&#xff0c;收敛相对更容易&#xff0c;经过batch normalization处理后的网络会提升2%的map&#xff0c;从现在的角度来看&#xff…

六万字77道Spring面试题总结(2024版)

文章目录 问题1&#xff1a;什么是Spring?问题2&#xff1a;Spring的两大核心概念是什么&#xff1f;问题3&#xff1a;Spring框架的设计目标、设计理念和核心是什么&#xff1f;问题4&#xff1a;Spring的优缺点是什么&#xff1f;问题5&#xff1a;Spring有哪些应用场景&…

数据结构与算法分析:你真的理解排序算法吗——中值排序(万字长文+代码详解)

一、算法描述 在计算机科学中&#xff0c;分治是一种非常常见的方法&#xff0c;它将一个问题分成两个独立的子问题&#xff0c;每个子问题的规模是原始问题规模的一般。将两个原始数组细分成两个不同的子数组&#xff0c;每个子数组的大小是原始大小的一半&#xff0c;这两个…

docker配置mysql8报错 ERROR 2002 (HY000)

通过docker启动的mysql&#xff0c;发现navicat无法连接&#xff0c;后来进入容器内部也是无法连接&#xff0c;产生以下错误 root9f3b90339a14:/var/run/mysqld# mysql -u root -p Enter password: ERROR 2002 (HY000): Cant connect to local MySQL server through socket …

《利用合成数据从临床数据仓库中自动检测脑部T1加权磁共振图像中的运动伪影》|文献速递-基于生成模型的数据增强与疾病监测应用

Title 题目 Automatic motion artefact detection in brain T1-weighted magnetic resonance images from a clinical data warehouse using synthetic data 《利用合成数据从临床数据仓库中自动检测脑部T1加权磁共振图像中的运动伪影》 Background 背景 近年来&#xff0…

校园电气火灾的精准防控“智”胜未来

在知识的殿堂里&#xff0c;每一缕光明都承载着未来的希望&#xff0c;而电力的稳定与安全&#xff0c;则是这希望之光的坚实基石。近年来&#xff0c;随着高校规模的不断扩大与电气化设备的日益增多&#xff0c;电力系统的安全保障成为了不容忽视的重大课题。电气火灾&#xf…

使用DQL命令查询数据(一)

DQL DQL(Data Query Language&#xff0c;数据查询语言)&#xff1a; 查询数据库数据&#xff0c;如SELECT语句。 简单的单表查询或多表的复杂查询和嵌套查询。 数据库语言中最核心、最重要的语句。 使用频率最高的语句。 SELECT语句&#xff1a; SELECT [ALL|DISTINCT] { *…