Java使用itext非模板方式生成PDF表格文件2

简介: Java使用itext非模板方式生成PDF表格文件2

由于基于模板生成pdf文件的方式,无法灵活支持同类别不固定行数的信息展示,所以只能改为不依靠模板的方式。现将我开发实现过程,做一简单分享。算是一个总结,便于自己日后查阅,也希望能够帮助到其他有需要的同学。


需要参考的,看一下我下面截图的结果样式,再看一下对应的测试代码就可以使用了。


1. 生成结果样式


网络异常,图片无法展示
|


pdf表格文件示例


2. 生成PDF文件实现方式


具体实现:


2.1 引入jar包

<dependency>
     <groupId>com.itextpdf</groupId>
     <artifactId>itextpdf</artifactId>
     <version>5.5.13</version>
</dependency>
<dependency>
     <groupId>com.itextpdf</groupId>
     <artifactId>itext-asian</artifactId>
     <version>5.2.0</version>
</dependency>


2.2 具体代码如下:


不啰嗦直接上代码,具体含义如果不清楚的话,可以看注释,我已经把注释尽可能的写详细了。

package pdfgentest;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileOutputStream;
public class PdfTableGenTest {
    private static Font headFont;// 设置字体大小
    private static Font sonHeadFont;// 设置字体大小
    private static Font normalTextFont;// 设置字体大小
    private static Font tableLineHeadFont;// 设置字体大小
    private static Font tableColumHeadFont;// 设置字体大小
    private static Font textFont;// 设置字体大小
    private static Font minTextFont;// 设置字体大小
    static {
        BaseFont bfChinese;
        try {
            bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            headFont = new Font(bfChinese, 16, Font.BOLD);// 设置字体大小
            sonHeadFont = new Font(bfChinese, 10, Font.BOLD);// 设置字体大小
            normalTextFont = new Font(bfChinese, 10, Font.NORMAL);// 设置字体大小
            tableLineHeadFont = new Font(bfChinese, 8, Font.BOLD);// 设置字体大小
            tableColumHeadFont = new Font(bfChinese, 6, Font.BOLD);// 设置字体大小
            textFont = new Font(bfChinese, 6, Font.NORMAL);// 设置字体大小
            minTextFont = new Font(bfChinese, 5, Font.NORMAL);// 设置字体大小
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void writeExampaperPdf() throws Exception {
        // 1.新建document对象
        // 第一个参数是页面大小。接下来的参数分别是左、右、上和下页边距。
        Document document = new Document(PageSize.A4, 50, 50, 20, 40);
        // 2.建立一个书写器(Writer)与document对象关联,通过书写器(Writer)可以将文档写入到磁盘中。
        // 创建 PdfWriter 对象 第一个参数是对文档对象的引用,第二个参数是文件的实际名称,在该名称中还会给出其输出路径。
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("D://myPdfFile.pdf"));
        //3.2打开文档
        document.open();
        //创建一个包含多列的表格,以通过合并单元格的方式,控制表格的宽度大小
        PdfPTable table = createTable(12);
        table.addCell(createCell("\n", headFont, Element.ALIGN_CENTER, 4, false));
        table.addCell(createCell("客户基本信息表", headFont, Element.ALIGN_CENTER, 4, false));
        sonHeadFont.setColor(new BaseColor(205, 133, 63)); //设置字体颜色
        table.addCell(createCell("文件编号:FILEBH-001", sonHeadFont, Element.ALIGN_RIGHT, 4, false));
        PdfPCell jbxxCell = createCell("基本信息", tableLineHeadFont, Element.ALIGN_CENTER, 12, true);
        jbxxCell.setBackgroundColor(new BaseColor(205, 133, 63));
        table.addCell(jbxxCell);
        //创建单元格,指定字体、对齐方式、合并单元格的个数、是否有边框
        table.addCell(createCell("姓名", tableColumHeadFont, Element.ALIGN_CENTER, 2, true));
        table.addCell(createCell(null, textFont, Element.ALIGN_CENTER, 4, true));
        table.addCell(createCell("职业", tableColumHeadFont, Element.ALIGN_CENTER, 2, true));
        table.addCell(createCell("工程师", textFont, Element.ALIGN_CENTER, 4, true));
        table.addCell(createCell("出生日期", tableColumHeadFont, Element.ALIGN_CENTER, 2, true));
        table.addCell(createCell("2020-01-01", textFont, Element.ALIGN_CENTER, 4, true));
        table.addCell(createCell("国籍", tableColumHeadFont, Element.ALIGN_CENTER, 2, true));
        table.addCell(createCell("中国", textFont, Element.ALIGN_CENTER, 4, true));
        table.addCell(createCell("性别", tableColumHeadFont, Element.ALIGN_CENTER, 2, true));
        table.addCell(createCell("男", textFont, Element.ALIGN_CENTER, 4, true));
        table.addCell(createCell("联系电话", tableColumHeadFont, Element.ALIGN_CENTER, 2, true));
        table.addCell(createCell("18888888888", textFont, Element.ALIGN_CENTER, 4, true));
        table.addCell(createCell("个人税收居民身份", tableColumHeadFont, Element.ALIGN_CENTER, 2, true));
        Phrase phrase = new Phrase();
        PdfPCell wtrgrssjmxxCell1 = new PdfPCell();
        wtrgrssjmxxCell1.setVerticalAlignment(Element.ALIGN_MIDDLE);
        wtrgrssjmxxCell1.setHorizontalAlignment(Element.ALIGN_LEFT);
        phrase.add(new Chunk("□ 1.中国税收居民      □ 2.非中国税收居民      ■ 3.既是中国税收居民又是其他国家(地区)税收居民\n", minTextFont).setLineHeight(12f));
        phrase.add(new Chunk("★ 如以上选项中填选第2项或第3项,请填写下列信息:\n", textFont).setLineHeight(12f));
        phrase.add(new Chunk("   税收居民国(地区):", textFont).setLineHeight(12f));
        phrase.add(new Chunk(" HK00001", textFont).setLineHeight(12f).setUnderline(0.5f, -1f));
        phrase.add(new Chunk("     纳税人识别号(如有):", textFont).setLineHeight(12f));
        phrase.add(new Chunk("289000001", textFont).setLineHeight(12f).setUnderline(0.5f, -1f)); //设置下划线,并设置下划线的粗细
        wtrgrssjmxxCell1.setPhrase(phrase);
        wtrgrssjmxxCell1.setPaddingLeft(20f);
        wtrgrssjmxxCell1.setColspan(10);
        wtrgrssjmxxCell1.setPaddingTop(3.0f);
        wtrgrssjmxxCell1.setPaddingBottom(6.0f);
        table.addCell(wtrgrssjmxxCell1);
        PdfPCell cclyCell = createCell("保险清单列表", tableLineHeadFont, Element.ALIGN_CENTER, 12, true);
        cclyCell.setBackgroundColor(new BaseColor(205, 133, 63)); //设置单元格背景
        table.addCell(cclyCell);
        for (int i = 0; i < 2; i++) {
            table.addCell(createCell("保险清单" + (i + 1), tableColumHeadFont, Element.ALIGN_CENTER, 2, true));
            Phrase insurancePhrase1 = new Phrase();
            PdfPCell insuranceCell1 = new PdfPCell();
            insuranceCell1.setVerticalAlignment(Element.ALIGN_MIDDLE); //上下居中
            insuranceCell1.setHorizontalAlignment(Element.ALIGN_LEFT); //水平左对齐
            insurancePhrase1.add(new Chunk("1.保险产品名称:灵通万事家天下寿险" + i + "\n", textFont).setLineHeight(10f)); //setLineHeight 设置行高
            insurancePhrase1.add(new Chunk("3.保险单号:L000000002392997" + i + "\n", textFont).setLineHeight(10f));
            insurancePhrase1.add(new Chunk("5.保险险种:终身寿险" + "\n", textFont).setLineHeight(10f));
            insurancePhrase1.add(new Chunk("7.基本保额:250000" + i + "\n", textFont).setLineHeight(10f));
            insurancePhrase1.add(new Chunk("9.备注(其他情况说明):无", textFont).setLineHeight(10f));
            insuranceCell1.setPhrase(insurancePhrase1);
            insuranceCell1.setPaddingLeft(10f);//设置左侧空白填充的宽度
            insuranceCell1.setColspan(5); //合并单元格
            insuranceCell1.setPaddingTop(1.0f); //距离上边框距离
            insuranceCell1.setPaddingBottom(4.0f); //距离下边框距离
            insuranceCell1.disableBorderSide(8);//隐藏右边框 1-上, 2-下, 4-左, 8-右
            table.addCell(insuranceCell1);
            Phrase insurancePhrase2 = new Phrase();
            PdfPCell insuranceCell2 = new PdfPCell();
            insuranceCell2.setVerticalAlignment(Element.ALIGN_MIDDLE); //上下居中
            insuranceCell2.setHorizontalAlignment(Element.ALIGN_LEFT); //水平左对齐
            insurancePhrase2.add(new Chunk("2.保险公司:灵通万事" + i + "\n", textFont).setLineHeight(10f));
            insurancePhrase2.add(new Chunk("4.保单生效日:2020/12/0" + i + "\n", textFont).setLineHeight(10f));
            insurancePhrase2.add(new Chunk("6.应交总保费:1290500" + i + "\n", textFont).setLineHeight(10f));
            insurancePhrase2.add(new Chunk("8.受益人变更情况:生存受益人变更为保险公司;身故受益人变更为保险公司\n", textFont).setLineHeight(10f));
            insurancePhrase2.add(new Chunk("              \n", textFont).setLineHeight(10f));
            insuranceCell2.setPhrase(insurancePhrase2);
            insuranceCell2.setColspan(5);
            insuranceCell2.setPaddingTop(1.0f);
            insuranceCell2.setPaddingBottom(4.0f);
            insuranceCell2.disableBorderSide(4);//隐藏左边框: 1-上, 2-下, 4-左, 8-右
            table.addCell(insuranceCell2);
        }
        PdfPCell syrmxCell = createCell("受益人情况", tableLineHeadFont, Element.ALIGN_CENTER, 12, true);
        syrmxCell.setBackgroundColor(new BaseColor(205, 133, 63));
        table.addCell(syrmxCell);
        for (int i = 0; i < 1; i++) {
            table.addCell(createCell("受益人" + (i + 1), tableColumHeadFont, Element.ALIGN_CENTER, 1, true));
            Phrase syrPhrase1 = new Phrase();
            PdfPCell syrCell1 = new PdfPCell();
            syrCell1.setVerticalAlignment(Element.ALIGN_MIDDLE);
            syrCell1.setHorizontalAlignment(Element.ALIGN_LEFT);
            syrPhrase1.add(new Chunk("姓名:王小" + i + "\n", textFont).setLineHeight(10f));
            syrPhrase1.add(new Chunk("与委托人关系:儿子\n", textFont).setLineHeight(10f));
            syrPhrase1.add(new Chunk("婚姻状况:未婚\n", textFont).setLineHeight(10f));
            syrPhrase1.add(new Chunk("联系电话:1887878000" + i + "\n", textFont).setLineHeight(10f));
            syrPhrase1.add(new Chunk("电子邮箱:8888888@168.com\n", textFont).setLineHeight(10f));
            syrPhrase1.add(new Chunk("邮寄地址:北京市朝阳区光明路128号5栋102\n", textFont).setLineHeight(10f));
            syrPhrase1.add(new Chunk("终止分配比例:100%", textFont).setLineHeight(10f));
            syrCell1.setPhrase(syrPhrase1);
            syrCell1.setPaddingLeft(10f);
            syrCell1.setColspan(5);
            syrCell1.setPaddingTop(1.0f);
            syrCell1.setPaddingBottom(4.0f);
            table.addCell(syrCell1);
            table.addCell(createCell("个人税收居民身份", tableColumHeadFont, Element.ALIGN_CENTER, 1, true));
            Phrase syrgrssjmxxPhrase = new Phrase();
            PdfPCell syrgrssjmxxCell1 = new PdfPCell();
            syrgrssjmxxCell1.setVerticalAlignment(Element.ALIGN_MIDDLE);
            syrgrssjmxxCell1.setHorizontalAlignment(Element.ALIGN_LEFT);
            syrgrssjmxxPhrase.add(new Chunk("■ 1.中国税收居民  □ 2.非中国税收居民 □ 3.既是中国又是其他国家(地区)税收居民\n", minTextFont).setLineHeight(15f));
            syrgrssjmxxPhrase.add(new Chunk("★ 如以上选项中填选第2项或第3项,请填写下列信息:\n", textFont).setLineHeight(15f));
            syrgrssjmxxPhrase.add(new Chunk("   税收居民国(地区):▁▁▁▁     纳税人识别号(如有):▁▁▁▁", textFont).setLineHeight(15f));
            syrgrssjmxxCell1.setPhrase(syrgrssjmxxPhrase);
            syrgrssjmxxCell1.setPaddingLeft(6f);
            syrgrssjmxxCell1.setColspan(5);
            syrgrssjmxxCell1.setPaddingTop(3.0f);
            syrgrssjmxxCell1.setPaddingBottom(6.0f);
            table.addCell(syrgrssjmxxCell1);
        }
        document.add(table);
        document.add(new Paragraph("\n"));
        String paragraph5 = "客户(签字):▁▁▁▁▁▁▁▁";
        Paragraph elements5 = new Paragraph(paragraph5, normalTextFont);
        elements5.setAlignment(Element.ALIGN_RIGHT);
        document.add(elements5);
        // 5.关闭文档
        document.close();
    }
    public static PdfPTable createTable(int colNumber) {
        int maxWidth = 500;
        PdfPTable table = new PdfPTable(colNumber);
        try {
            table.setTotalWidth(maxWidth);
            table.setLockedWidth(true);
            table.setHorizontalAlignment(Element.ALIGN_CENTER);
            table.setWidths(new int[]{50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50});
            table.getDefaultCell().setBorder(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return table;
    }
    public static PdfPCell createCell(String value, Font font, int align, int colspan, boolean boderFlag) {
        PdfPCell cell = new PdfPCell();
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.setHorizontalAlignment(align);
        cell.setColspan(colspan);
        cell.setPhrase(new Phrase(value, font));
        cell.setPadding(3.0f);
        if (!boderFlag) {
            cell.setBorder(0);
            cell.setPaddingTop(15.0f);
            cell.setPaddingBottom(8.0f);
        }
        return cell;
    }
    public static void main(String[] args) {
        try {
            writeExampaperPdf();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


3. 写在最后的小心得


网上得来的代码,尤其是涉及流资源读取与关闭的,一定要仔细重点的经过反复测试验证之后,再借鉴使用。一定不要拿来主义,直接照搬。因为很多时候看似是捷径的方法,其实质很可能是拖你后腿的大坑。


4. 参考文章


https://www.bbsmax.com/A/gVdnK17XzW/

https://www.cnblogs.com/qlqwjy/p/8213989.html

相关文章
|
18天前
|
文字识别 Serverless 开发工具
【全自动改PDF名】批量OCR识别提取PDF自定义指定区域内容保存到 Excel 以及根据PDF文件内容的标题来批量重命名
学校和教育机构常需处理成绩单、报名表等PDF文件。通过OCR技术,可自动提取学生信息并录入Excel,便于统计分析和存档管理。本文介绍使用阿里云服务实现批量OCR识别、内容提取、重命名及导出表格的完整步骤,包括开通相关服务、编写代码、部署函数计算和设置自动化触发器等。提供Python示例代码和详细操作指南,帮助用户高效处理PDF文件。 链接: - 百度网盘:[链接](https://pan.baidu.com/s/1mWsg7mDZq2pZ8xdKzdn5Hg?pwd=8866) - 腾讯网盘:[链接](https://share.weiyun.com/a77jklXK)
54 5
|
18天前
|
文字识别
【PDF提取全自动改名】如何批量提取PDF指定区域的文字内容,用内容批量给PDF命名或者导出表格,学会全自动解放双手
在生活和工作中,我们常需处理大量PDF文件,如银行单据、税收单据等。手动处理效率低下,而使用“咕嘎批量PDF多区域内容提取重命名导表格系统”可快速完成数千份文档的处理,大幅提高效率。该工具通过获取PDF各区域内容坐标,导入并处理文件,最终将信息提取至表格,并根据关键信息对PDF进行重命名,方便管理和查找。
43 2
|
22天前
|
Java API 数据处理
深潜数据海洋:Java文件读写全面解析与实战指南
通过本文的详细解析与实战示例,您可以系统地掌握Java中各种文件读写操作,从基本的读写到高效的NIO操作,再到文件复制、移动和删除。希望这些内容能够帮助您在实际项目中处理文件数据,提高开发效率和代码质量。
27 4
|
1月前
|
文字识别 BI
【图片型PDF】批量识别扫描件PDF指定区域局部位置内容,将识别内容导出Excel表格或批量改名文件,基于阿里云OCR对图片型PDF识别改名案例实现
在医疗和政务等领域,图片型PDF文件(如病历、报告、公文扫描件)的处理需求广泛。通过OCR技术识别这些文件中的文字信息,提取关键内容并保存为表格,极大提高了信息管理和利用效率。本文介绍一款工具——咕嘎批量OCR系统,帮助用户快速处理图片型PDF文件,支持区域识别、内容提取、导出表格及批量改名等功能。下载工具后,按步骤选择处理模式、进行区域采样、批量处理文件,几分钟内即可高效完成数百个文件的处理。
132 8
|
1月前
|
人工智能 编解码 文字识别
OCRmyPDF:16.5K Star!快速将 PDF 文件转换为可搜索、可复制的文档的命令行工具
OCRmyPDF 是一款开源命令行工具,专为将扫描的 PDF 文件转换为可搜索、可复制的文档。支持多语言、图像优化和多核处理。
240 17
OCRmyPDF:16.5K Star!快速将 PDF 文件转换为可搜索、可复制的文档的命令行工具
|
1月前
|
存储 算法 Java
解锁“分享文件”高效密码:探秘 Java 二叉搜索树算法
在信息爆炸的时代,文件分享至关重要。二叉搜索树(BST)以其高效的查找性能,为文件分享优化提供了新路径。本文聚焦Java环境下BST的应用,介绍其基础结构、实现示例及进阶优化。BST通过有序节点快速定位文件,结合自平衡树、多线程和权限管理,大幅提升文件分享效率与安全性。代码示例展示了文件插入与查找的基本操作,适用于大规模并发场景,确保分享过程流畅高效。掌握BST算法,助力文件分享创新发展。
|
5天前
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
55 23
|
12天前
|
Java 调度
【源码】【Java并发】【线程池】邀请您从0-1阅读ThreadPoolExecutor源码
当我们创建一个`ThreadPoolExecutor`的时候,你是否会好奇🤔,它到底发生了什么?比如:我传的拒绝策略、线程工厂是啥时候被使用的? 核心线程数是个啥?最大线程数和它又有什么关系?线程池,它是怎么调度,我们传入的线程?...不要着急,小手手点上关注、点赞、收藏。主播马上从源码的角度带你们探索神秘线程池的世界...
81 0
【源码】【Java并发】【线程池】邀请您从0-1阅读ThreadPoolExecutor源码
|
16天前
|
存储 监控 Java
【Java并发】【线程池】带你从0-1入门线程池
欢迎来到我的技术博客!我是一名热爱编程的开发者,梦想是编写高端CRUD应用。2025年我正在沉淀中,博客更新速度加快,期待与你一起成长。 线程池是一种复用线程资源的机制,通过预先创建一定数量的线程并管理其生命周期,避免频繁创建/销毁线程带来的性能开销。它解决了线程创建成本高、资源耗尽风险、响应速度慢和任务执行缺乏管理等问题。
142 60
【Java并发】【线程池】带你从0-1入门线程池
|
1月前
|
Java 程序员 开发者
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
106 14

热门文章

最新文章