使用IText导出复杂pdf

news2024/11/19 1:26:00

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 {
    @Autowired
    private MyItextpdfUtils myItextpdfUtils;

    @Test
    public 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

 

 

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

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

相关文章

基于阿里云 Flink+Hologres 搭建实时数仓

摘要&#xff1a;本文作者阿里云 Hologres 高级研发工程师张高迪&阿里云 Flink 技术内容工程师张英男&#xff0c;本篇内容将为您介绍如何通过实时计算 Flink 版和实时数仓 Hologres 搭建实时数仓。 Tips&#xff1a;点击「阅读原文」免费领取 5000CU*小时 Flink 云资源 背…

Linux Debian12命令终端安装pip install rsa报错error: externally-managed-environment

Linux Debian12在命令终端安装pip install rsa出现error: externally-managed-environment错误,如下图&#xff1a; 仔细读了一下报错内容才搞懂&#xff0c;原来是Debian12安装Python包时需要使用apt install python3-包名&#xff0c;例如安装rsa&#xff0c;使用sudo apt …

太阳能的发展与应用

目录 1.太阳能的概念 2.太阳能的原理 3.太阳能的发展过程 4.太阳能的普及对人类的作用 1.太阳能的概念 太阳能是指利用太阳辐射能的能源。太阳能可以分为两种利用方式&#xff1a;热能和光能。 太阳能热能是指将太阳辐射的热能直接转化为热能供人们使用。这种利用方式包括太…

导出Excel一些格式、样式的 代码

1.合并单元格 // 合并单元格&#xff08;开始行, 结束行, 开始列, 结束列&#xff09;CellRangeAddress regionRow0 new CellRangeAddress(0, 0, 0, 10);sheet.addMergedRegion(regionRow0);2.单元格根据汉字自动匹配颜色 HSSFConditionalFormattingRule orange scf.createCo…

SE24维护类、接口interface(如何看懂CO03事务码对应的abap代码)

我想读懂CO03这个事务码的代码。 也不是全都读懂&#xff0c;只要读懂其中一小部分就可以了。如下图&#xff1a; 记入文档的货物移动。 现在已经大概知道了这种SAP系统自带事务码的代码结构&#xff0c;因为我想看懂的部分&#xff0c;毕竟是其中最简单的部分-----ALV&#…

大疆mini 3 Pro 手工拍摄倾斜摄影照片, 利用WebODM 制作老房子的模型

最近比较着迷于无人机&#xff0c; 因此也研究了一些无人机图片的处理技术&#xff0c; 对于航空倾斜摄影的图片处理&#xff0c; 发现WebODM 这个开源软件确实不错&#xff0c; 利用手里的大疆mini 3 pro&#xff0c; 手动拍摄了一些关于家里的老房子的照片&#xff0c; 最后果…

MFC140.dll缺失的修复方法,安装MFC140.dll文件

大家好&#xff0c;今天我要和大家分享的是如何正确安装和使用MFC140.dll。MFC140.dll是一种常见的动态链接库文件&#xff0c;它是Microsoft Foundation Classes(MFC)的一部分&#xff0c;被广泛应用于Windows操作系统中的各种应用程序中。在本文中&#xff0c;我们将详细介绍…

什么是高度塌陷?

目录 高度塌陷 解决高度塌陷的方法 由于前面将高度塌陷和外边距重叠搞混&#xff0c;现在重新写一下高度塌陷 高度塌陷 在文档流中&#xff0c;父元素的高度默认是被子元素撑开的&#xff0c;也就是子元素多高&#xff0c;父元素就多高。但是当为子元素设置浮动以后&#xff…

win10的pycharm开发工具使用Jupyter的各种报错:环境问题

一、问题 在win10系统的pycharm开发工具使用Jupyter的各种报错&#xff0c;却一直解决不了。 我一度使用过购买云服务器、重装系统等等各种办法&#xff0c;都没能解决。 例如&#xff1a;在speech_processing.ipynb文件中 import librosa y, sr librosa.load(C:/Test/000…

基于Forcite模块的分子动力学研究药剂与矿物相互作用实例(一)

关键词&#xff1a;相互作用 MS Forcite 分子动力学 径向分布 笔名&#xff1a;杨过 Forcite模块是分子动力学计算的主要模块&#xff0c;研究范围广&#xff0c;可以对多种周期性体系进行计算分析&#xff0c;在矿物分选领域中主要是计算分析药剂与矿物相互作用&#xff0…

ROS2中的roscd命令

一、问题 最近在学习ROS2&#xff0c;环境搭建好后想查看下某个包的内容&#xff0c;在ROS里面习惯用roscd直接进入&#xff0c;但在ROS2里面没有这个命令 二、解决办法 目前网上的相关资料比较少&#xff0c;博客1中提到ROS2中需要使用colcon_cd来替代roscd&#xff0c;不过…

LeetCode 热题 100(五):54. 螺旋矩阵、234. 回文链表、21. 合并两个有序链表

题目一&#xff1a; 54. 螺旋矩阵https://leetcode.cn/problems/spiral-matrix/ 题目要求&#xff1a; 思路&#xff1a;一定要先找好边界。如下图 &#xff0c;上边界是1234&#xff0c;右边界是8、12&#xff0c;下边界是9、10、11&#xff0c;左边界是5&#xff0c;所以可…

机器人TF坐标系变换与一些可视化工具的应用

TF坐标在ROS中是一个非常重要的概念&#xff0c;因为机器人在做日常操作任务的时候&#xff0c;对于其所在位置和朝向是需要时刻知道的&#xff0c;而机器人是由很多节点组成的协同任务&#xff0c;对于每个部件&#xff0c;我们需要知道它的位姿(位置和朝向)&#xff0c;这使得…

Vue初识别--环境搭建--前置配置过程

问题一&#xff1a; 在浏览器上的扩展程序上添加了vue-devtools后不生效&#xff1a; 解决方式&#xff1a;打开刚加入的扩展工具Vue.js devtools的允许访问文件地址设置 问题二&#xff1a;Vue新建一个项目 创建一个空文件夹hrsone&#xff0c;然后在VSCode中打开这个空文件夹…

操作系统-笔记-第二章-进程同步与互斥

目录 二、第二章——【进程同步与互斥】 1、进程同步&#xff08;异步&#xff09; 2、进程互斥 & 共享 3、总结&#xff08;互斥、同步&#xff09; 4、进程互斥&#xff08;软件实现&#xff09; &#xff08;1&#xff09;单标志法——谦让【会让他们轮流访问、其…

李沐pytorch学习-卷积网络及其实现

一、卷积定义 卷积计算过程如图1所示&#xff0c;即输入矩阵和核函数对应的位置相乘&#xff0c;然后相加得到输出对应位置的数。 图1. 卷积计算过程 该过程可以形象地从图2中展现。 图2. 二维卷积示意图 二、代码实现 2.1 实现互相关运算 import torch from torch import n…

CANoe软件Tools中无法找到LDF Explorer

关联文章&#xff1a; LDF概述和LDF Explorer工具介绍 问题描述 使用CANoe软件的菜单栏Tools中无法找到LDF Explorer 原因分析/解决方案&#xff1a; ①查看CANoe硬件是否带LIN license&#xff0c;并且license在正常激活时间内。 ②查看CANoe是否配置了LIN通道&#xff0c;…

嵌入式设备应用开发(程序构建)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 编译是嵌入式开发很重要的一个环节。记得早年在上海一家通讯公司上班的时候,单位还专门有一个人维护编译脚本。当时用的是makefile,这位同学的主要工作就是替大家维护好各个项目的…

设备绑定驱动

头文件 驱动程序 应用程序 串口实现LED灯亮灭

postgresql 数据排序

postgresql 常见操作 排序总结 排序 -- 排序的时候null是最大的值(看一下) select employee_id,manager_id from employeesorder by manager_id desc;-- nulls first使null值排在第一位 select employee_id,manager_id from employeesorder by manager_id nulls first;-- null…