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