需要的jar

            <!-- freemarker,生成 html --><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.28</version></dependency><!-- 渲染 css 样式 --><dependency><groupId>org.xhtmlrenderer</groupId><artifactId>flying-saucer-pdf</artifactId><version>9.1.16</version></dependency><!-- iText,export pdf --><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13</version></dependency>

资源文件处理工具类

import org.springframework.util.ResourceUtils;import java.io.File;
import java.io.FileNotFoundException;/*** @Description: 项目静态资源文件工具类*     仅可用于包含在web项目中的资源文件路径,资源文件必须放置于 web 模块下* @Author: junqiang.lu* @Date: 2019/1/4*/
public class ResourceFileUtil {/*** 获取资源文件** @param relativePath 资源文件相对路径(相对于 resources路径,路径 + 文件名)*                     eg: "templates/pdf_export_demo.ftl"* @return* @throws FileNotFoundException*/public static File getFile(String relativePath) throws FileNotFoundException {if (relativePath == null || relativePath.length() == 0) {return null;}if (relativePath.startsWith("/")) {relativePath = relativePath.substring(1);}File file = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX+ relativePath);return file;}/*** 获取资源绝对路径** @param relativePath 资源文件相对路径(相对于 resources路径,路径 + 文件名)*                     eg: "templates/pdf_export_demo.ftl"* @return* @throws FileNotFoundException*/public static String getAbsolutePath(String relativePath) throws FileNotFoundException {return getFile(relativePath).getAbsolutePath();}/*** 获取资源父级目录** @param relativePath 资源文件相对路径(相对于 resources路径,路径 + 文件名)*                     eg: "templates/pdf_export_demo.ftl"* @return* @throws FileNotFoundException*/public static String getParent(String relativePath) throws FileNotFoundException {return getFile(relativePath).getParent();}/*** 获取资源文件名** @param relativePath 资源文件相对路径(相对于 resources路径,路径 + 文件名)*                     eg: "templates/pdf_export_demo.ftl"* @return* @throws FileNotFoundException*/public static String getFileName(String relativePath) throws FileNotFoundException {return getFile(relativePath).getName();}}

PDF 生成工具类

import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.BaseFont;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;import java.io.*;
import java.util.Map;/*** @Description: pdf 导出工具类* @Author: junqiang.lu* @Date: 2018/12/25*/
public class PDFUtil {private PDFUtil(){}private volatile static Configuration configuration;static {if (configuration == null) {synchronized (PDFUtil.class) {if (configuration == null) {configuration = new Configuration(Configuration.VERSION_2_3_28);}}}}/*** freemarker 引擎渲染 html** @param dataMap 传入 html 模板的 Map 数据* @param ftlFilePath html 模板文件相对路径(相对于 resources路径,路径 + 文件名)*                    eg: "templates/pdf_export_demo.ftl"* @return*/public static String freemarkerRender(Map<String, Object> dataMap, String ftlFilePath) {Writer out = new StringWriter();configuration.setDefaultEncoding("UTF-8");configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);try {configuration.setDirectoryForTemplateLoading(new File(ResourceFileUtil.getParent(ftlFilePath)));configuration.setLogTemplateExceptions(false);configuration.setWrapUncheckedExceptions(true);Template template = configuration.getTemplate(ResourceFileUtil.getFileName(ftlFilePath));template.process(dataMap, out);out.flush();return out.toString();} catch (IOException e) {e.printStackTrace();} catch (TemplateException e) {e.printStackTrace();} finally {try {out.close();} catch (IOException e) {e.printStackTrace();}}return null;}/*** 使用 iText 生成 PDF 文档** @param htmlTmpStr html 模板文件字符串* @param fontFile 所需字体文件(相对路径+文件名)* */public static byte[] createPDF(String htmlTmpStr, String fontFile) {ByteArrayOutputStream outputStream = null;byte[] result = null;try {outputStream = new ByteArrayOutputStream();ITextRenderer renderer = new ITextRenderer();renderer.setDocumentFromString(htmlTmpStr);ITextFontResolver fontResolver = renderer.getFontResolver();// 解决中文支持问题,需要所需字体(ttc)文件fontResolver.addFont(ResourceFileUtil.getAbsolutePath(fontFile),BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);renderer.layout();renderer.createPDF(outputStream);result=outputStream.toByteArray();if(outputStream != null) {outputStream.flush();outputStream.close();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (DocumentException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return result;}}

PDF 导出所需资源文件
PDF 导出需要 freemarker 的渲染模板 ftl 文件

关于 ftl 模板的一些信息: ftl 模板使用和 html 一致的标签,和 html 不同的是 ftl 模板文件可以添加独有的逻辑元算标签, 如 if-else, for 等,逻辑运算标签具体可参考 freemarker 官方文档:

https://freemarker.apache.org/docs/ref_directives.html

这是我的模板:pz.ftl

<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>Title</title><style>@page {size: 279mm 216mm;}table.pzjbt {border-collapse:collapse;border-color:#0094b5;border-style:solid;border-width:1px;margin-bottom:3px;margin-top:3px;text-align: center;}td.pzjbt {border-left-width:1px;border-left-style:solid;border-left-color:#000000;border-top-width:1px;border-top-style:solid;border-top-color:#000000;border-right-width:1px;border-right-style:solid;border-right-color:#000000;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#000000;padding-top:1px;padding-bottom:1px;padding-left:1px;padding-right:1px;vertical-align:top;text-align: center;}p.pzdl {color:#000000;font-family:NSimSun;font-size:12px;font-style:normal;font-variant:normal;font-weight:300;line-height:1.2;margin-bottom:0;margin-left:0;margin-right:0;margin-top:0;orphans:1;page-break-after:auto;page-break-before:auto;text-align:center;text-align-last:center;text-decoration:none;text-indent:0;text-transform:none;widows:1;}td.CellOverride-1 {border-bottom-color:#199fbc;border-bottom-style:solid;border-bottom-width:1px;border-left-color:#0094b5;border-left-style:solid;border-left-width:1px;border-right-color:#0094b5;border-right-style:solid;border-right-width:1px;border-top-color:#0094b5;border-top-style:solid;border-top-width:2px;vertical-align:middle;}td.CellOverride-2 {border-bottom-color:#0094b5;border-bottom-style:solid;border-bottom-width:1px;border-left-color:#199fbc;border-left-style:solid;border-left-width:1px;border-right-color:#191919;border-right-style:solid;border-right-width:0px;border-top-color:#199fbc;border-top-style:solid;border-top-width:1px;vertical-align:middle;}td.CellOverride-3 {border-bottom-color:#0094b5;border-bottom-style:solid;border-bottom-width:1px;border-left-color:#191919;border-left-style:solid;border-left-width:0px;border-right-color:#0094b5;border-right-style:solid;border-right-width:1px;border-top-color:#0094b5;border-top-style:solid;border-top-width:1px;vertical-align:middle;}td.CellOverride-4 {border-bottom-color:#0094b5;border-bottom-style:solid;border-bottom-width:1px;border-left-color:#199fbc;border-left-style:solid;border-left-width:1px;border-right-color:#191919;border-right-style:solid;border-right-width:0px;border-top-color:#0094b5;border-top-style:solid;border-top-width:1px;vertical-align:middle;}td.CellOverride-5 {border-bottom-color:#199fbc;border-bottom-style:solid;border-bottom-width:1px;border-left-color:#199fbc;border-left-style:solid;border-left-width:1px;border-right-color:#191919;border-right-style:solid;border-right-width:0px;border-top-color:#0094b5;border-top-style:solid;border-top-width:1px;vertical-align:middle;}td.CellOverride-6 {background-color:#0094b5;border-bottom-style:solid;border-bottom-width:0px;border-left-style:solid;border-left-width:0px;border-right-color:#0094b5;border-right-style:solid;border-right-width:1px;border-top-color:#199fbc;border-top-style:solid;border-top-width:1px;vertical-align:middle;}td.CellOverride-7 {background-color:#0094b5;border-bottom-style:solid;border-bottom-width:0px;border-left-color:#0094b5;border-left-style:solid;border-left-width:1px;border-right-color:#0094b5;border-right-style:solid;border-right-width:1px;border-top-color:#199fbc;border-top-style:solid;border-top-width:1px;vertical-align:middle;}td.CellOverride-8 {background-color:#0094b5;border-bottom-style:solid;border-bottom-width:0px;border-left-style:solid;border-left-width:0px;border-right-style:solid;border-right-width:0px;border-top-color:#0094b5;border-top-style:solid;border-top-width:1px;vertical-align:middle;}p.ParaOverride-1 {text-align:center;text-align-last:center;}p.ParaOverride-2 {text-align:left;}span.CharOverride-1 {color:#191919;font-family:NSimSun;font-style:normal;font-weight:normal;}span.CharOverride-2 {font-family:NSimSun;font-size:9px;font-style:normal;font-weight:normal;}span.CharOverride-3 {color:#f5760a;font-family:NSimSun;font-size:9px;font-style:normal;font-weight:300;}span.CharOverride-4 {font-family:NSimSun;font-style:normal;font-weight:300;}td._idGenCellOverride-1 {border-right-style:solid;border-right-width:0px;}col._idGenTableRowColumn-1 {width:81px;}col._idGenTableRowColumn-2 {width:35px;}col._idGenTableRowColumn-3 {width:45px;}tr._idGenTableRowColumn-4 {min-height:26px;}tr._idGenTableRowColumn-5 {min-height:23px;}tr._idGenTableRowColumn-6 {min-height:31px;}img._idGenObjectAttribute-1 {height:25px;width:57px;}img._idGenObjectAttribute-2 {height:20px;width:46px;}</style></head>
<body><div id="_idContainer002" style="width: 1000px;"><table id="table001" class="pzjbt" style="width: 100%;margin-left: 20%;"><colgroup><col class="_idGenTableRowColumn-1" /><col class="_idGenTableRowColumn-2" /><col class="_idGenTableRowColumn-3" /><col class="_idGenTableRowColumn-1" /><col class="_idGenTableRowColumn-1" /></colgroup><tr class="pzjbt _idGenTableRowColumn-4"><td class="pzjbt CellOverride-1" colspan="5"><p class="pzdl ParaOverride-1"><span class="CharOverride-1">收  据</span></p></td></tr><tr class="pzjbt _idGenTableRowColumn-5"><td class="pzjbt CellOverride-2" colspan="2"><p class="pzdl ParaOverride-1"><span class="CharOverride-2">日期</span></p></td><td class="pzjbt CellOverride-3" colspan="3"><p class="pzdl ParaOverride-1"><span class="CharOverride-3">${(createTime?string("yyyy-MM-dd HH:mm:ss"))!}</span></p></td></tr><tr class="pzjbt _idGenTableRowColumn-5"><td class="pzjbt CellOverride-4" colspan="2"><p class="pzdl ParaOverride-1"><span class="CharOverride-2">交易编号</span></p></td><td class="pzjbt CellOverride-3" colspan="3"><p class="pzdl ParaOverride-1"><span class="CharOverride-3">${orderCode!''}</span></p></td></tr><tr class="pzjbt _idGenTableRowColumn-5"><td class="pzjbt CellOverride-4" colspan="2"><p class="pzdl ParaOverride-1"><span class="CharOverride-2">交易类型</span></p></td><td class="pzjbt CellOverride-3" colspan="3"><p class="pzdl ParaOverride-1"><span class="CharOverride-3">捐赠</span></p></td></tr><tr class="pzjbt _idGenTableRowColumn-5"><td class="pzjbt CellOverride-4" colspan="2"><p class="pzdl ParaOverride-1"><span class="CharOverride-2">交易金额</span></p></td><td class="pzjbt CellOverride-3" colspan="3"><p class="pzdl ParaOverride-1"><span class="CharOverride-3">${productPrice!0}</span></p></td></tr><tr class="pzjbt _idGenTableRowColumn-5"><td class="pzjbt CellOverride-5" colspan="2"><p class="pzdl ParaOverride-1"><span class="CharOverride-2">付款人</span></p></td><td class="pzjbt CellOverride-3" colspan="3"><p class="pzdl ParaOverride-1"><span class="CharOverride-3">${userName!''}</span></p></td></tr></table>
</div></body>
</html>

html前端入口

 <a  href="${basePath}/exportPdf?orderId=${saleOrder.id}">下载</a>

Controller 层

@RequestMapping(value = "/exportPdf", method = {RequestMethod.POST, RequestMethod.GET},produces = MediaType.MULTIPART_FORM_DATA_VALUE)public ResponseEntity<?> exportPdf(Long orderId){try {SaleOrderVo saleOrder = saleOrderExtService.getSaleOrderById(orderId);ResponseEntity<?> responseEntity = export(saleOrder);return responseEntity;} catch (Exception e) {e.printStackTrace();}HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON_UTF8);return new ResponseEntity<String>("{ \"code\" : \"404\", \"message\" : \"not found\" }",headers, HttpStatus.NOT_FOUND);}/*** PDF 文件导出** @return*/public ResponseEntity<?> export(SaleOrderVo saleOrder) {HttpHeaders headers = new HttpHeaders();/*** 数据导出(PDF 格式)*/Map<String, Object> dataMap = new HashMap<>(16);dataMap.put("createTime",saleOrder.getCreateTime());dataMap.put("orderCode",saleOrder.getOrderCode());dataMap.put("productPrice",saleOrder.getProductPrice());dataMap.put("userName",saleOrder.getUserName());String htmlStr = PDFUtil.freemarkerRender(dataMap, "templates/website/pz/pz.ftl");InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("templates/website/pz/simsun.ttc");// htmlStr = htmlStr.replaceAll("<br>", "");//htmlStr = htmlStr.replaceAll("</br>", "");byte[] pdfBytes = PDFUtil.createPDF(htmlStr, "templates/website/pz/simsun.ttc");if (pdfBytes != null && pdfBytes.length > 0) {String fileName = UUID.randomUUID() + ".pdf";headers.setContentDispositionFormData("attachment", fileName);headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);return new ResponseEntity<byte[]>(pdfBytes, headers, HttpStatus.OK);}headers.setContentType(MediaType.APPLICATION_JSON_UTF8);return new ResponseEntity<String>("{ \"code\" : \"404\", \"message\" : \"not found\" }",headers, HttpStatus.NOT_FOUND);}

simsun.ttc字体文件  :链接:https://pan.baidu.com/s/1UO6uSKaL-DERaFYaqZqs8g  密码:yhdo

点击下载效果

遇到的错误

simsun.ttc  is not a valid TTF file

原因:问题是Maven正在过滤字体文件并破坏它们。

pom.xml加入

          <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><configuration><nonFilteredFileExtensions><nonFilteredFileExtension>ttf</nonFilteredFileExtension><nonFilteredFileExtension>woff</nonFilteredFileExtension><nonFilteredFileExtension>woff2</nonFilteredFileExtension></nonFilteredFileExtensions></configuration></plugin>

参考文章: http://www.mamicode.com/info-detail-2411295.html

参考文章:https://blog.csdn.net/Mrqiang9001/article/details/86241836

springboot html 动态数据转pdf相关推荐

  1. Java动态数据生成PDF文档及下载

    查了很多资料都没有我想要的pdf,于是根据iText基础知识(这里是看了宝爷的笔记点击打开链接)自行编辑了一个简单的表格pdf文档 运用spring.mybatis.CXF框架 SSM框架打印pdf: ...

  2. Java word动态数据填充并转为pdf最详细的讲解附带项目

    Java Word数据动态填充,并将word转为pdf 适用范围: 1.已有word模板,word中的一些数据需要动态生成. 2.word转为pdf 本文章讲解的内容是一个完整的适用流程.就是首先是一 ...

  3. 使用Freemark和aspose.word实现动态word转pdf

    前言 因为公司业务需要实现业务人员提供wodr模板,然后系统填充数据生成pdf文件,本文的想法是通过Freemark填充数据生成word再通过aspose.word把word文档转为pdf文档. 本文 ...

  4. Springboot构建Echarts数据可视化

    Spring boot集成了tomcat等容器,效率更高,要实现数据的可视化,需要构建spring Boot框架架构web项目.同时使用注意的方式,就可以轻松建立前端访问路径与后端controller ...

  5. springboot validated注解数据校验 异常处理

    springboot validated 数据校验 validated 数据校验 简单的写一下这个用法啊,清晰的本篇文章就记录这个注解的一个用法. validated 数据校验 我们一般的数据校验是怎 ...

  6. 添加数据功能java,SpringBoot+Vue实现数据添加功能

    一.添加代码生成器 用来自动为数据库映射类建立:mapper.service.controller package com.hanmh.utils; import com.baomidou.mybat ...

  7. python使用fpdf生成数据报告pdf文件

    python使用fpdf生成数据报告pdf文件 目录 python使用fpdf生成数据报告pdf文件 # 报告生成整体代码

  8. Keras用动态数据生成器(DataGenerator)和fitgenerator动态训练模型

    有了这个生成器,我们就可以用fit_generator 方法进行训练,格式套路如下: model.fit_generator(generator, steps_per_epoch=..., epoch ...

  9. C#应用NPOI实现导出EXcel表格中插入饼状图(可实现动态数据生成)

    一.思路:   1.excel是可以通过NPOI插入图片的: 2.C#通过NPOI生成饼状图: 3.把生成的饼状图以字节流的形式插入到表格 二.看代码: #region 生成饼图图例/// <s ...

最新文章

  1. spark1.x和2.xIterable和iterator兼容问题
  2. 用JSLint精炼提升JavaScript代码
  3. [密码学基础][每个信息安全博士生应该知道的52件事][Bristol52]40一般来说SPA和DPA的区别是什么
  4. MySQL源码解读之数据结构-LF_DYNARRAY
  5. zoj 1088 System Overload
  6. 阿里最后一面,高并发下如何设计一个秒杀系统?
  7. 屌丝创业从理性“认识你自己”开始
  8. VRF抽签与投票的思考
  9. QT - 图像处理 ( 1 ) - QImage像素级操作 - (转灰度、亮度、暖色、冷色、饱和度、模糊、锐化、金属效果 )
  10. 英语学(xiao 二声)习__字母读音
  11. 案例-canvas绘制雨滴
  12. 面试中的老大难 - MySQL中的锁
  13. 【JY】YJK前处理参数详解及常见问题分析(一)
  14. (网页)HTML小技巧的一些小技巧
  15. 上大学的四年---以此结束四年的时光
  16. 三星Note 7惊魂48天:产品质量比创新和体验更重要
  17. 如何在hexo上创建一篇文章
  18. DxOMARK如何测试音频质量?小编带你答疑解惑
  19. LeetCode 1430. Check If a String Is a Valid Sequence from Root to Leaves Path in a Binary Tree
  20. 关于高三经典励志文章精选

热门文章

  1. 喜讯|慧灵科技 荣获维科杯·OFweek2022中国机器人行业年度市场突破奖
  2. 世界顶级计算机专家排名,世界前1000名顶级计算机科学家名单出炉,美国616人,中国呢?...
  3. DxO PureRAW for Mac(RAW照片处理器)
  4. java word上传下载_java poi 上传与下载word文件
  5. Python 机器学习:超参数调优
  6. 笔记四:Java基础阶段结束,用GUI实现的美女拼图游戏
  7. 分布式事务之Seata常见异常
  8. 英语基础---并列句
  9. 嵌入式开发ARM Cortex-M33处理器详解
  10. 2021物联之星年度评选公布评选结果。核芯物联凭借全球首发的无线全网通蓝牙AOA定位基站GA30荣获2021物联之星年度评选“最佳创新产品奖”