springboot 动态导出pdf

springboot 动态导出pdf

原理是通过freemarker插入数据到html模版里面,html你就叫前端帮你写好,他不写你就告诉你主管让他叫他写,你只管往预留的位置插入数据就行,然后通过itextpdf会将准备好html文件转成PDF。

### 1、准备依赖

        <!--下载pdf begin--><dependency><groupId>com.itextpdf</groupId><artifactId>html2pdf</artifactId><version>4.0.3</version></dependency><!-- freemarker模版 --><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.30</version></dependency><!--下载pdf end-->

### 2、准备html模版

<html>
<head><meta charset="UTF-8"><style>.main-container {font-family: SF-UI-Text-Regular;width: 21cm;margin: 0 auto;padding: 20px;}.float-left {float: left;}.float-right {float: right;}.padding-left-right {padding-left: 20px;padding-right: 20px;}.margin-left-right {margin-left: 20px;margin-right: 20px;}.section {/*border: 3px dashed #CCC;*//*padding: 20px;*/border-Top: 2px dashed #D3D3D3;padding-Top: 13px;margin-bottom: 16px;margin-Top: 20px;}.section-details p {color: #126089;/*font-size: 16px;*/}.grouper {overflow: hidden;}.grid-50 {width: 50%;}@font-face {font-family: 'SF-UI-Text-Regular';src: url("https://s3-ap-southeast-1.amazonaws.com/content.staging.whitecoat.global/PDF/Templates/fonts/SF-UI-Text-Regular.otf");font-style: normal;}h1 {font-size: 22px;font-family: 'SF-UI-Text-Regular';}.h1-main {margin-top: 90px;}p {margin: 0 0 10px 0;font-family: 'SF-UI-Text-Regular';font-size: 12px;}.p-spec {color: #149a9a;font-weight: bold;}table, th, td {padding: 5px;border-collapse: collapse;}th, td {border: 1px solid #D3D3D3;}.margin-b-30 {margin-bottom: 30px;}.row:after {content: "";display: table;clear: both;}.column-4 {float: left;width: 33.33%;padding: 10px;}.column-8 {float: left;width: 66.66%;padding: 10px;}* {box-sizing: border-box;font-size: 12px;}</style>
</head>
<body><div class="main-container"><div style="background-color: #fff"><div class="grouper main-header grouper padding-left-right" style="padding-top: 20px"><div class="margin-b-30 row"><div class="column-4"><img style="max-width:90%"src="https://s3-ap-southeast-1.amazonaws.com/content.staging.whitecoat.global/PDF/Templates/Images/WhiteCoat_Tax_Invoice.png"></div><div class="column-4">WhiteCoat Holdings Pte Ltd. <br/>Clinic Licence No.: 18M0119/01/182 <br/>201 Henderson Road #05-11/12 <br/>Apex @ Henderson <br/>Singapore 159545 <br/></div><div class="column-4">GST Reg. No: 201610235E <br/>T: +65 6909 6909 <br/>F: +65 6909 6909 <br/>E: contactus@whitecoat.com.sg <br/><a style="text-decoration: none;" href="https://whitecoat.com.sg/">whitecoat.com.sg</a></div></div></div><div class="main-body"><div class="grouper"><div class="grouper margin-left-right row" style="border-Top: 1px solid #D3D3D3;padding-top:20px;"><div class="column-4">Name: <br/>${data.name!} <br/><br/>NRIC/FIN/Passport No: <br/>${data.idNo!}</div><div class="column-8">Invoice No.: <br/>${data.invoiceNo!} <br/><br/>Invoice Date: <br/>${data.invoiceDateStr!} <br/><br/><i>This is a computer generated invoice. No signature is required.</i></div></div><div class="grouper margin-left-right" style="border-Top: 1px solid #D3D3D3;padding-top:20px;"><table><tr><th>S/N</th><th colspan="2">Description</th><th style="border:1px solid #D3D3D3;">Amount</th></tr><tr><td style="width:30px;text-align:center;">1</td><td style="width:550px; border-right: none">Medication <br/><#list data.medicationList as item>${item.productName!} <br/></#list><i><br/>Subtotal</i></td><td style="text-align:right; border-left: none">Quantity <br/><#list data.medicationList as item>${item.quantity!} <br/></#list><i style="color:#fff"><br/>Subtotal</i></td><td style="width:200px;text-align:right"><br/><#list data.medicationList as item>$${item.amount!} <br/></#list><br/><i>${data.subtotal!}</i></td></tr><tr><td style="text-align:center;">2</td><td colspan="2">Administrative charges</td><td style="text-align:right">$${data.adminCharge!}</td></tr><tr><td colspan="3" style="text-align:right; border-bottom: none; border-left: none">Subtotal(Excluding GST)</td><td style="text-align:right">$${data.subtotalExcludingGST!}</td></tr><tr><td colspan="3"style="text-align:right; ; border-bottom: none; border-top: none; border-left: none">GST(${data.tax!}%)</td><td style="text-align:right">$${data.GST!}</td></tr><tr><td colspan="3"style="text-align:right; border-top: none; border-left: none; border-bottom: none">Total(Including GST)</td><td style="text-align:right">$${data.totalIncludingGST!}</td></tr></table></div><div class="grouper margin-left-right float-left" style="padding-bottom :20px;padding-top :20px"><span>Bank remittance details for payment by Bank Telegraphic <br/>Transfer in Singapore Dollars to:<br/>Name of Bank: United Overseas Bank Ltd. Holland Branch<br/>Account Name: Whitecoat Holdings Pte Ltd.<br/>Account No: 341-308-316-6<br/>Bank Code: 7375<br/>Branch Code: 020<br/>Bank Swift Code: UOVBSGSG</span></div></div></div></div></body>
</html>

### 3、下载代码

    @ApiOperation(value = "下载pdf")@GetMapping("downloadPDF/staffPurchase")public ResponseResult download(String id, HttpServletResponse response) throws Exception {StaffPurchasePDFVo data = staffPurchaseMapper.getStaffPurchasePDFData(id);HashMap<String, Object> mapData = Maps.newHashMap();mapData.put("data", data);long timeMillis = System.currentTimeMillis();String templateContent = HtmlUtils.getTemplateContent("Staff_Purchase_Receipt.ftl", mapData);HtmlUtils.html2Pdf(response, templateContent, timeMillis + "");return ResponseResult.success();}

### 4、htmlutils代码

import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.layout.font.FontProvider;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Map;
import java.util.Objects;@Slf4j
public class HtmlUtils {/*** @return* @throws Exception*/public static String getTemplateDirectory() {ClassLoader classLoader = HtmlUtils.class.getClassLoader();URL resource = classLoader.getResource("templates");try {return Objects.requireNonNull(resource).toURI().getPath();} catch (URISyntaxException e) {log.error("获取模板文件夹失败,{}", e);}return null;}/*** 获取模板内容** @param templateName 模板文件名* @param paramMap     模板参数* @return* @throws Exception*/public static String getTemplateContent(String templateName, Map<String, Object> paramMap) throws Exception {Configuration config = ApplicationContextUtil.getBean(FreeMarkerConfigurer.class).getConfiguration();config.setDefaultEncoding("UTF-8");Template template = config.getTemplate(templateName, "UTF-8");return FreeMarkerTemplateUtils.processTemplateIntoString(template, paramMap);}/*** HTML 转 PDF** @param content html内容* @param outPath 输出pdf路径* @return 是否创建成功*/public static boolean html2Pdf(String content, String outPath) {try {ConverterProperties converterProperties = new ConverterProperties();converterProperties.setCharset("UTF-8");FontProvider fontProvider = new FontProvider();fontProvider.addSystemFonts();converterProperties.setFontProvider(fontProvider);HtmlConverter.convertToPdf(content, new FileOutputStream(outPath), converterProperties);} catch (Exception e) {log.error("生成模板内容失败,{}", e);return false;}return true;}/*** HTML 转 PDF** @param content html内容* @return PDF字节数组*/public static void html2Pdf(HttpServletResponse response, String content,String filename) throws IOException {response.setHeader("Content-Type", "application/octet-stream");response.setCharacterEncoding("utf-8");response.setHeader("Content-Disposition", "attachment;filename="+filename+".pdf");try (ServletOutputStream outputStream = response.getOutputStream()) {ConverterProperties converterProperties = new ConverterProperties();converterProperties.setCharset("UTF-8");FontProvider fontProvider = new FontProvider();fontProvider.addSystemFonts();converterProperties.setFontProvider(fontProvider);HtmlConverter.convertToPdf(content, outputStream, converterProperties);} catch (Exception e) {log.error("生成 PDF 失败,{}", e);}}
} 

ApplicationContextUtil代码、

import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;@Configuration
@AutoConfigureOrder(-1)
public class ApplicationContextUtil implements ApplicationContextAware {private static ApplicationContext applicationContext = null;public static Object getBeanByName(String beanName) {if (applicationContext == null) {return null;}return applicationContext.getBean(beanName);}public static <T> T getBean(Class<T> type) {return applicationContext.getBean(type);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {ApplicationContextUtil.applicationContext = applicationContext;}}

5、freemarker的基本语法

https://developer.aliyun.com/article/942606

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/654220.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

思维题之T恤衫

[ABC332C] T-shirts - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 源于atcoder 由于字符串的长度为1000.不论怎样&#xff0c;顺序枚举即可。 import java.awt.FontFormatException; import java.awt.geom.AffineTransform; import java.awt.image.BandCombineOp; import …

自定义注解实现动态数据源

在Java开发中&#xff0c;使用多数据源能够提高系统的灵活性和性能。本文将通过介绍自定义注解的方式&#xff0c;实现动态数据源的切换。通过这种创新性的方法&#xff0c;开发者可以根据业务需求轻松切换数据库连接&#xff0c;实现数据源的动态管理&#xff0c;提升系统的可…

C++类和对象(中)

✨Blog&#xff1a;&#x1f970;不会敲代码的小张:)&#x1f970; &#x1f251;推荐专栏&#xff1a;C语言&#x1f92a;、Cpp&#x1f636;‍&#x1f32b;️、数据结构初阶&#x1f480; &#x1f4bd;座右铭&#xff1a;“記住&#xff0c;每一天都是一個新的開始&#x1…

如何在Win系统安装Jupyter Notbook并实现无公网ip远程访问本地笔记

文章目录 1.前言2.Jupyter Notebook的安装2.1 Jupyter Notebook下载安装2.2 Jupyter Notebook的配置2.3 Cpolar下载安装 3.Cpolar端口设置3.1 Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 在数据分析工作中&#xff0c;使用最多的无疑就是各种函数、图表、…

Mybatis-Plus基础

typora-copy-images-to: img Mybatis Plus 今日目标&#xff1a; 了解mybatisplus的特点能够掌握mybatisplus快速入门能够掌握mybatisplus常用注解能够掌握mybatisplus常用的增删改查能够掌握mybatisplus自动代码生成 1 MybatisPlus简介 1.1 MybatisPlus概述 ​ MyBatis-…

【前端web入门第二天】03 表单-下拉菜单 文本域 label标签 按钮 【附注册信息综合案例】

文章目录: 1. 下拉菜单 2. 文本域3.label标签 4.按钮- button 4.1 reset重置按钮结合form表单区域使用 5.无语义的布局标签 6.字符实体 注册信息综合案例 表单第二节 1. 下拉菜单 标签: select嵌套option,select是下拉菜单整体&#xff0c;option是下拉菜单的每一项。 代码…

MySQL运维实战(5.1) 字符和编码的基本概念

作者&#xff1a;俊达 字符和编码 字符 字符是符号&#xff0c;是人们用于交流的各类符号&#xff0c;如26个英文字母、汉字、标点符号、数学运算符、其他语言的字母和符号。 编码 编码是计算机中以二进制方式存储字符的方式。每个字符都有一个对应的编码值&#xff0c;计算机…

HarmonyOS --@state状态装饰器

在声明式UI中&#xff0c;是以状态驱动视图更新。 状态&#xff08;state&#xff09;&#xff1a;指驱动视图更新的数据&#xff08;被装饰器标记的变量&#xff09;。 试图&#xff08;view&#xff09;&#xff1a;基于UI描述渲染得到用户界面 State装饰器标记的变量必须初…

FPGA硬件架构

1.Xilinx FPGA是异构计算平台&#xff08;所谓异构&#xff0c;就是有很多不同的部分组成&#xff09;&#xff1a;CLB,BRAM,DSP 2. 软核&#xff1a; 把经过功能验证的、可综合的、实现后电路结构总门数在五千门以上的Verilog HDL模型称为软核(soft core)。 硬核: 把在某一…

数字化人才培养-流量的认知

1、流量的分类 公域/商域/私域 公域&#xff1a;公域流量指商家直接入驻平台实现流量转换&#xff0c;比如大家熟悉的拼多多、京东、淘宝、饿了么等&#xff0c;以及内容付费行业的喜马拉雅、知乎、得到等公域流量平台。 公域流量典型的代表有&#xff1a;抖音视频的曝光量、…

JavaScript DOM属性和方法之attribute属性对象

在HTML的DOM中&#xff0c;attribute对象表示HTML属性。HTML属性始终属于HTML元素&#xff0c;它在DOM节点中被称为属性节点。在DOM中&#xff0c;NamedNodeMap对象表示元素属性节点的无序集合&#xff0c;我们可以通过指定的索引访问指定的属性。通过element对象的attribute属…

小红树上染色

记忆化深搜 #include <iostream> #include <string> #include <stack> #include <vector> #include <queue> #include <deque> #include <set> #include <map> #include <unordered_map> #include <unordered_set&g…

JAVAEE初阶 网络编程(六)

TCP协议 一. 四次挥手二. 连接管理过程中TCP状态的变化2.1 listen状态2.2 established状态2.3 CLOSE_WAIT状态2.4 TIME_WAIT状态 三. 滑动窗口3.1 ack丢了3.2 数据丢了 一. 四次挥手 我们都知道&#xff0c;在三次握手中是可以把中间步骤合并成一个步骤执行&#xff0c;那么在四…

C语言数据结构(4)——线性表其三(双向链表)

欢迎来到博主的专栏——C语言数据结构 博主ID&#xff1a;代码小豪 文章目录 链表的种类头结点循环链表双向链表带头双向循环链表带头双向循环链表的定义与初始化 空链表尾插法打印双向链表头插法查找指定数据项的节点在指定位置之后插入节点指定位置的删除双向链表的销毁 顺序…

C语言第十二弹--扫雷

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 扫雷 1、扫雷游戏分析和设计 1.1、扫雷游戏的功能说明 1.2 游戏的分析和设计 1.2.1、数据结构的分析 1.2.2、文件结构设计 2、扫雷游戏的结构分析 2.1、用…

vmware虚拟机centos8共享文件夹挂载

1.设置虚拟机共享文件夹 2. 上述设置完毕之后&#xff0c;重启进入虚拟机&#xff0c;查看出现的共享文件夹名称 vmware-hgfsclient 3.查看是否有挂载目录&#xff0c;挂在目录默认为 /mnt/hgfs。没有时可以使用以下命令创建 mkdir /mnt/hgfs 4. 手动挂载目录--只能实现一次 注…

LarkXR引入2D共享模式,CloudXR新体验

Paraverse平行云自主研发的LarkXR&#xff0c;作为CloudXR解决方案的领军者&#xff0c;已在业界实现了显著的创新突破。LarkXR通过分钟级部署大规模云端资源、高度适配所有主流XR引擎&#xff0c;并灵活支持不同的交互和沉浸方式&#xff0c;成功地解决了Cloud XR商业化过程中…

Arduino Uno R3通过ESP-01S连接网络

一、材料准备 Arduino Uno R3开发板 1 USB串口通信数据线&#xff08;Uno开发板使用&#xff09; 1 ESP8266-01S Wi-Fi模块 1 ESP8266固件烧录下载器&#xff08;烧录固件使用&#xff09; 1 WiFi无线收发转接板&#xff08;适用于ESP-01S、ESP-01&#xff09; 杜邦线…

java设计模式:工厂模式

1&#xff1a;在平常的开发工作中&#xff0c;我们可能会用到不同的设计模式&#xff0c;合理的使用设计模式&#xff0c;可以提高开发效率&#xff0c;提高代码质量&#xff0c;提高系统的可拓展性&#xff0c;今天来简单聊聊工厂模式。 2&#xff1a;工厂模式是一种创建对象的…

如何查看某网站的谷歌流量的组成情况

在独立站跨境贸易当中&#xff0c;很多时候我们都会重复一个动作&#xff0c;那就是查看对手网站或者某一网站的流量&#xff0c;以此来分析和总结如何优化自己的站点&#xff0c;借鉴对手优秀的地方来补足自己的缺点&#xff0c;或者某些时候会模仿甚至抄袭竞品网站。那么如何…