使用IText导出复杂pdf
1、问题描述
需要将发票导出成pdf,要求每页都必须包含发票信息和表头行。
2、解决方法
使用IText工具实现PDF导出
IText8文档:Examples (itextpdf.com)
3、我的代码
引入Itext依赖,我这里用的是8.0.1版本
<dependency><groupId>com.itextpdf</groupId><artifactId>itext7-core</artifactId><version>8.0.1</version><type>pom</type></dependency>
MyItextpdfUtils.java
package com.easyexcel.util;import com.easyexcel.handler.PaginationEventHandler;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.properties.AreaBreakType;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** @author Wulc* @date 2023/8/10 17:08* @description*/
@Component
public class MyItextpdfUtils {public void createPDF() throws java.io.IOException {Resource resource = new ClassPathResource("/");String path = resource.getFile().getPath();//设置中文字体 C:\Windows\Fonts//PdfFont chineseFont =getFont();//PdfFont chineseFont = PdfFontFactory.createFont(this.getClass().getClassLoader().getResource("simsun.ttf").getPath());PdfFont chineseFontForTemplate = PdfFontFactory.createFont("D:\\学习资料\\后端\\STSONG.TTF");PdfFont chineseFontForContent = PdfFontFactory.createFont("D:\\学习资料\\后端\\STSONG.TTF");//创建每页的共有模板//*********************每页的共有模板*********************************String templatePath = path + "\\template.pdf";PdfDocument pdfDocumentTemplate = new PdfDocument(new PdfWriter(templatePath));//Document documentTemplate = new Document(pdfDocumentTemplate, PageSize.A4).setFont(chineseFontForTemplate);Document documentTemplate = new Document(pdfDocumentTemplate, PageSize.A4);//插入logo图片Table logoTemplateTable = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth().setBorder(Border.NO_BORDER);ImageData imageData = ImageDataFactory.create(this.getClass().getClassLoader().getResource("logo.png"));Image image = new Image(imageData);image.setHeight(50);image.setWidth(100);logoTemplateTable.addCell(new Cell().setBorder(Border.NO_BORDER).add(image));//插入logo图片下方的一些信息Table logoInfoTable = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth().setBorder(Border.NO_BORDER);logoInfoTable.addCell(new Cell().setBorder(Border.NO_BORDER).setPadding(1).setFontSize(10).add(new Paragraph("Description1")));logoInfoTable.addCell(new Cell().setBorder(Border.NO_BORDER).setPadding(1).setFontSize(10).add(new Paragraph("Description2")));logoInfoTable.addCell(new Cell().setBorder(Border.NO_BORDER).setPadding(1).setFontSize(10).add(new Paragraph("Description3")));//插入标题Table titleTable = new Table(UnitValue.createPercentArray(4)).useAllAvailableWidth().setBorder(Border.NO_BORDER);titleTable.addCell(new Cell(1, 4).setBorder(Border.NO_BORDER).setPadding(1).setFontSize(15).add(new Paragraph("TITLE")).setTextAlignment(TextAlignment.CENTER));//插入标题下的一些信息Table titleInfoTable = new Table(UnitValue.createPercentArray(4)).useAllAvailableWidth();titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("QuestionA")));titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("AnswerA")));titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("QuestionB")));titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("AnswerB")));titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("QuestionC")));titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("AnswerC")));titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("QuestionD")));titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("AnswerD")));titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("QuestionE")));titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("AnswerE")));titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("QuestionF")));titleInfoTable.addCell(new Cell().setPadding(1).setFontSize(10).add(new Paragraph("AnswerF")));documentTemplate.add(logoTemplateTable);documentTemplate.add(logoInfoTable);documentTemplate.add(titleTable);documentTemplate.add(titleInfoTable);//*********************每页的共有模板*********************************//*********************每页的内容************************************String contentPath = path + "\\content.pdf";PdfDocument pdfDocumentContent = new PdfDocument(new PdfWriter(contentPath));//把内容使用共有模板pdfDocumentContent.addEventHandler(PdfDocumentEvent.END_PAGE, new PaginationEventHandler(pdfDocumentTemplate.getFirstPage().copyAsFormXObject(pdfDocumentContent)));Document documentContent = new Document(pdfDocumentContent, PageSize.A4).setFont(chineseFontForContent);//每页的content距离上面的template的距离documentContent.setTopMargin(250);Table contentTable = new Table(UnitValue.createPercentArray(6)).useAllAvailableWidth();//插入清单表格标题contentTable.addHeaderCell(new Cell().setFontSize(8).add(new Paragraph("No")));contentTable.addHeaderCell(new Cell().setFontSize(8).add(new Paragraph("title1")));contentTable.addHeaderCell(new Cell().setFontSize(8).add(new Paragraph("title2")));contentTable.addHeaderCell(new Cell().setFontSize(8).add(new Paragraph("title3")));contentTable.addHeaderCell(new Cell().setFontSize(8).add(new Paragraph("title4")));contentTable.addHeaderCell(new Cell().setFontSize(8).add(new Paragraph("title5")));for (int i = 0; i < 300; i++) {contentTable.addCell(new Cell().setFontSize(8).add(new Paragraph(String.valueOf(i))));contentTable.addCell(new Cell().setFontSize(8).add(new Paragraph("content1")));contentTable.addCell(new Cell().setFontSize(8).add(new Paragraph("content2")));contentTable.addCell(new Cell().setFontSize(8).add(new Paragraph("content3")));contentTable.addCell(new Cell().setFontSize(8).add(new Paragraph("content4")));contentTable.addCell(new Cell().setFontSize(8).add(new Paragraph("content5")));}//尾页Table lastInfoTable = new Table(UnitValue.createPercentArray(3)).setWidth(300);lastInfoTable.addCell(new Cell(1, 3).setPadding(1).setFontSize(8).add(new Paragraph("Total:")));lastInfoTable.addCell(new Cell(1, 1).setPadding(1).setFontSize(8).add(new Paragraph("统计A:")));lastInfoTable.addCell(new Cell(1, 2).setPadding(1).setFontSize(8).add(new Paragraph("1234567")));lastInfoTable.addCell(new Cell(1, 1).setPadding(1).setFontSize(8).add(new Paragraph("统计B:")));lastInfoTable.addCell(new Cell(1, 2).setPadding(1).setFontSize(8).add(new Paragraph("7654321")));//*********************每页的内容************************************documentContent.add(contentTable);//尾页新开一页documentContent.add(new AreaBreak(AreaBreakType.NEXT_PAGE));documentContent.add(lastInfoTable);documentTemplate.close();documentContent.close();}}
PDFTest.java
package com.easyexcel;import com.easyexcel.util.MyItextpdfUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.io.IOException;/*** @author Wulc* @date 2023/8/10 17:52* @description*/
@SpringBootTest(classes = SpringbootApplication.class)
@RunWith(SpringRunner.class)
public class PDFTest {@Autowiredprivate MyItextpdfUtils myItextpdfUtils;@Testpublic void test6() throws IOException {myItextpdfUtils.createPDF();}
}
测试一下:
4、总结
IText8不支持中文,需要引入外部字体文件,如果是以其中一个pdf作为每页的背景模板生成PDF这种方式(copyAsFormXObject),它只能支持其中一个pdf中文,另一个就不支持了。
Document documentTemplate = new Document(pdfDocumentTemplate, PageSize.A4).setFont(chineseFontForTemplate);
Document documentContent = new Document(pdfDocumentContent, PageSize.A4).setFont(chineseFontForContent);
如上代码,虽然我同时把背景版和内容同时都设置了中文字体,但是template和content合一块的时候,template的背景版pdf的中文字体就会失效了。
不过还好,因为是海外的发票都是英文的,因此不需要考虑支持中文的问题。
希望哪位大佬能帮忙解决一下IText8 copyAsFormXObject中文兼容性问题!!!
5、参考资料
https://www.cnblogs.com/sky-chen/p/13026203.html#autoid-1-4-5-0-0-0
https://kb.itextpdf.com/home/it7kb/examples/repeating-parts-of-a-form
https://zhuanlan.zhihu.com/p/537723847
https://blog.csdn.net/weixin_43409994/article/details/118157694
https://blog.csdn.net/u012397189/article/details/126345744
https://blog.csdn.net/Thinkingcao/article/details/84988392
相关文章:

使用IText导出复杂pdf
1、问题描述 需要将发票导出成pdf,要求每页都必须包含发票信息和表头行。 2、解决方法 使用IText工具实现PDF导出 IText8文档:Examples (itextpdf.com) 3、我的代码 引入Itext依赖,我这里用的是8.0.1版本 <dependency><groupId>…...

多线程并发服务器(TCP)
服务器 客户端 结果...

uni-app的Vue.js实现微信小程序的紧急事件登记页面功能
主要功能实现 完成发生时间选择功能,用户可以通过日期选择器选择事件发生的时间。实现事件类型选择功能,用户可以通过下拉选择框选择事件的类型。添加子养殖场编号输入框,用户可以输入与事件相关的子养殖场编号。完成事件描述输入功能&#…...
面试题 17.16.按摩师
题目来源: leetcode题目,网址:面试题 17.16. 按摩师 - 力扣(LeetCode) 解题思路: 动态规划,对于第 i 个预约,若接下,其最大值为不接上一个时的最大值与当前值之和&a…...

vscode里配置C#环境并运行.cs文件
vscode是一款跨平台、轻量级、开源的IDE, 支持C、C、Java、C#、R、Python、Go、Nodejs等多种语言的开发和调试。下面介绍在vscode里配置C#环境。这里以配置.Net SDK v5.0,语言版本为C#9.0,对应的开发平台为VS2019,作为案例说明。 1、下载vsc…...

uniapp配置添加阿里巴巴图标icon流程步骤
文章目录 下载复制文件到项目文件夹里项目配置目录结构显示图标 下载 阿里巴巴icon官网 https://www.iconfont.cn/ 复制文件到项目文件夹里 项目配置目录结构 显示图标...

大模型基础02:GPT家族与提示学习
大模型基础:GPT 家族与提示学习 从 GPT-1 到 GPT-3.5 GPT(Generative Pre-trained Transformer)是 Google 于2018年提出的一种基于 Transformer 的预训练语言模型。它标志着自然语言处理领域从 RNN 时代进入 Transformer 时代。GPT 的发展历史和技术特点如下: GP…...
算法基础课——基础算法(模板整理)
快速排序 快速排序 #include <iostream> #include <algorithm> using namespace std; int n; int s[100000]; int main() {cin>>n;for(int i0;i<n;i){cin>>s[i];}sort(s,sn);for(int i0;i<n;i){cout<<s[i]<<" ";}cout<…...

如何解决使用npm出现Cannot find module ‘XXX\node_modules\npm\bin\npm-cli.js’错误
遇到问题:用npm下载组件时出现Cannot find module ‘D:software\node_modules\npm\bin\npm-cli.js’ 问题,导致下载组件不能完成。 解决方法:下载缺少的npm文件即可解决放到指定node_modules目录下即可解决。 分析问题࿱…...

【华为认证数通高级证书实验-分享篇2】
实验拓扑 注:代码块为各交换机路由器中的配置命令 配置拓扑文件 实验要求 实现全网通 实验配置 SW3 [SW3]v b 10 20 [SW3]int e0/0/1 [SW3-Ethernet0/0/1]po link-t a [SW3-Ethernet0/0/1]po de v 10 [SW3-Ethernet0/0/1]int e0/0/2 [SW3-Ethernet0/0/2]po li…...
ui设计需要学编程吗难不难学习 优漫动游
ui设计需要学编程吗难不难学习,对于基础小白来说学习编程确实有一定难度,所以很想知道零基础学习ui设计需要学编程吗,需不需要写代码呢,这些问题小编来简单的分析分析解决零基础小白的一些困惑,希望对你有帮助。 ui…...
什么是线程优先级?Java中的线程优先级是如何定义和使用的?
线程优先级是指在多线程环境中,通过给线程分配不同的优先级来决定线程获取CPU时间片的顺序。优先级较高的线程会更有可能被调度执行,而优先级较低的线程可能会获得较少的CPU时间。 在Java中,线程优先级是通过整数表示的,范围从1到…...

无涯教程-TensorFlow - XOR实现
在本章中,无涯教程将学习使用TensorFlow的XOR实现,在TensorFlow中开始XOR实施之前,看一下XOR表值。这将帮助了解加密和解密过程。 A B A XOR B 0 0 0 0 1 1 1 0 1 1 1 0 XOR密码加密方法基本上用于加密,即通过生成与适当密钥匹配…...

计算机组成与设计 Patterson Hennessy 笔记(二)MIPS 指令集
计算机的语言:汇编指令集 也就是指令集。本书主要介绍 MIPS 指令集。 汇编指令 算数运算: add a,b,c # abc sub a,b,c # ab-cMIPS 汇编的注释是 # 号。 由于MIPS中寄存器大小32位,是基本访问单位,因此也被称为一个字 word。M…...
【设计模式】模板方法模式(Template Method Pattern)
23种设计模式之模板方法模式(Template Method Pattern) 基本概念 模板方法模式是一种行为型设计模式,它定义了一个算法骨架,将某些算法步骤的实现延迟到子类中。 这样可以使得算法的框架不被修改,但是具体的实现可以…...

【潮州饶平】联想 IBM x3850 x6 io主板故障 服务器维修
哈喽 最近比较忙也好久没有更新服务器维修案例了,这次分享一例潮州市饶平县某企业工厂一台IBM System x3850 x6服务器亮黄灯告警且无法正常开机的服务器故障问题。潮州饶平ibm服务器维修IO主板故障问题 故障如下图所示: 故障服务器型号:IBM 或…...

【AIGC】 国内版聊天GPT
国内版聊天GPT 引言一、国内平台二、简单体验2.1 提问2.2 角色扮演2.3 总结画图 引言 ChatGPT是OpenAI发开的聊天程序,功能强大,可快速获取信息,节省用户时间和精力,提供个性化的服务。目前国产ChatGPT,比如文心一言&a…...
如何在Vue中进行单元测试?什么是Vue的模块化开发?
1、如何在Vue中进行单元测试? 在Vue中进行单元测试可以提高代码的可维护性和可读性,同时也能够帮助开发者更快地找到代码中的问题和潜在的错误。下面是一些在Vue中进行单元测试的步骤: 安装单元测试工具 首先需要安装一个单元测试工具&…...
Matlab编程示例3:Matlab求二次积分的编程示例
1.在MATLAB中,可以使用符号计算工具箱(Symbolic Math Toolbox)中的int函数来求解二次积分。 2.下面是一个简单的MATLAB程序示例,演示二次函数f (x,y) x^2 y^2,在x∈[0 1]和y∈[0 1]的积分区间上,计算积分结果: syms…...

【Linux】线程同步和死锁
目录 死锁 什么是死锁 构成死锁的四个必要条件 如何避免死锁 线程同步 同步的引入 同步的方式 条件变量 条件变量的使用 整体代码 死锁 什么是死锁 死锁是指在一组进程中的各个进程均占有不会释放的资源,但因互相申请被其他进程所占用不会释放 的资源而处…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...