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