itext5创建pdf表格及遇到的一些问题

2023-11-17

0. 核心依赖:

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

1. 设置页眉图片及下划线

通过PdfPageEventHelper事件可以动态的创建页眉,数据构建出多少页pdf就有多少页页眉

package com.example.pdf;

import com.example.pdf.vo.RenovationDocNameEnum;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;

/**
 * 内部类 添加页眉、页脚
 */
public class PdfEvent extends PdfPageEventHelper {

    // 一页加载完成触发,写入页眉和页脚
    @Override
    public void onEndPage(PdfWriter writer, Document document) {
        PdfPTable head = new PdfPTable(1);
        PdfObject businessType = document.getAccessibleAttribute(new PdfName("businessType"));
        PdfObject flag = document.getAccessibleAttribute(new PdfName("flag"));
        try {
            if (RenovationDocNameEnum.CB.getName().equals(businessType.toString())
                    || (RenovationDocNameEnum.SG.getName().equals(businessType.toString()) && flag != null && "1".equals(flag.toString()))) {
                setCbPageHead(head, writer, document);
            } else if (RenovationDocNameEnum.SG.getName().equals(businessType.toString()) || RenovationDocNameEnum.JC.getName().equals(businessType.toString())) {
                setSinglePageHead(head, writer, document);
            }
        } catch (Exception e) {
            throw new ExceptionConverter(e);
        }
    }

    /**
     * Chunk的offsetX控制页眉图片水平位置,offsetY会影响到图片大小; 图片上下位置可通过showTextAligned的y来控制
     * 页眉下划线通过setTotalWidth控制先长度,writeSelectedRows的xPos控制线的起始水平位置
     *
     * @param head
     * @param writer
     * @param document
     * @throws DocumentException
     */
    private void setSinglePageHead(PdfPTable head, PdfWriter writer, Document document) throws DocumentException {
        Font font = PdfUtil.getFont(null);
        // 通过表格构建页眉下划线
        head.setTotalWidth(PageSize.A4.getWidth() - 105);
        head.setWidths(new int[]{24});
        head.setLockedWidth(true);
        head.getDefaultCell().setFixedHeight(-10);
        head.getDefaultCell().setBorder(Rectangle.BOTTOM);
        head.getDefaultCell().setBorderWidth(0.5f);
        head.addCell(new Paragraph(" ", font));
        // 将页眉写到document中,位置可以指定,指定到下面就是页脚
        head.writeSelectedRows(0, -1, 55, PageSize.A4.getHeight() - 20, writer.getDirectContent());
        PdfContentByte directContent = writer.getDirectContent();
        // 最重要的是这个,如果页眉需要设置图片的话,需要在Phrase对象中添加一个Chunk对象,在Chunk对象中添加图片信息即可
        Phrase phrase = new Phrase("", font);
        Image img = PdfUtil.getImg();
        if (img != null) {
            phrase.add(new Chunk(img, 30, -150));
        }
        // 写入页眉
        ColumnText.showTextAligned(directContent, Element.ALIGN_RIGHT, phrase, document.right(), PageSize.A4.getHeight() + 48, 0);
    }
  • 通过PdfPTable来构建下划线
  • 通过new Chunk来显示图片,并通过ColumnText.showTextAligned来展示在页眉
  • 详细见setSinglePageHead方法的注释,方正就是一顿调,知道合适位置

2. document参数传递:

  • 像下述这样定义一个字符串参数于document,就可以像上述PdfEvent中获取做业务判断
  • 使用的时候注意toString()
PdfName businessType = new PdfName("businessType");
document.setAccessibleAttribute(businessType, new PdfString(type));

3. 生成的pdf文件转base64编码:

  • 主要以下两个方法,FileUtil是hutool的工具类,Base64是java.util的工具类

	PdfUtil.getBase64(FileUtil.readBytes(file));
	
    public static String getBase64(byte[] buffer) {
        return Base64.getEncoder().encodeToString(buffer);
    }

4. 平方²上标显示问题:

本人生成pdf时用的是simkai.ttf字体,输出的pdf没有显示²上标

  • 要么可以换字体,百度即可
  • 要么像如下这样,通过setTextRise来控制文字位置,来大概展示成²效果
  • 方法正值为上标,负值可为下标,注意上标的2的文字specialFont字体要定义小点,本人定义5
 public static PdfPCell getPDFCellSpecial(String name, Font font, Integer alignment) {
        PdfPCell cell = new PdfPCell();
        if (name == null) {
            name = " ";
        }
        Paragraph p = new Paragraph(name, font);
        Font specialFont = PdfUtil.getSpecialFont(null);
        Chunk chunk = new Chunk("2", specialFont);
        chunk.setTextRise(5f);
        p.add(chunk);
        p.add(new Chunk(")", font));

        if (alignment == null) {
            p.setAlignment(Element.ALIGN_CENTER);
        } else {
            p.setAlignment(alignment);
        }
        cell.setUseAscender(true);
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.addElement(p);
        return cell;
    }

5. 压缩包的文件流InputStream输出文件:

  • 业务上从别的接口获取到一个zip包的文件流,需要将zip包的文件输出到目录,如下代码:
  • 涉及IO流要注意关流

    private static List<String> extractAllByInputStream(InputStream inputStream, String pdfPath) {
        ArrayList<String> list = Lists.newArrayList();
        try {
            dealZipInputStream(inputStream, pdfPath, list);
        } catch (IOException e) {
            LOGGER.info("下载pdf到本地异常,异常信息:{}", e);
        }

        return list;
    }

    private static void dealZipInputStream(InputStream inputStream, String pdfPath, ArrayList<String> list) throws IOException {
        byte[] buffer = new byte[1024];
        ZipEntry zipEntry;
        try (ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                String entryName = zipEntry.getName();
                if (!zipEntry.isDirectory()) {
                    String fileName;
                    if (entryName.contains(RenovationDocNameEnum.CB.getName())) {
                        fileName = pdfPath + RenovationDocNameEnum.CB.getName() + ".pdf";
                    } else if (entryName.contains(RenovationDocNameEnum.JC.getName())) {
                        fileName = pdfPath + RenovationDocNameEnum.JC.getName() + ".pdf";
                    } else if (entryName.contains(RenovationDocNameEnum.SG.getName())) {
                        fileName = pdfPath + RenovationDocNameEnum.SG.getName() + ".pdf";
                    } else {
                        fileName = pdfPath + UUID.randomUUID() + ".pdf";
                    }
                    list.add(fileName);
                    File subFile = new File(fileName);
                    subFile.createNewFile();
                    readSubFile(subFile, zipInputStream, buffer);

                }
                zipInputStream.closeEntry();
            }
        } finally {
            IOUtils.closeQuietly(inputStream);
        }
    }

    private static void readSubFile(File subFile, ZipInputStream zipInputStream, byte[] buffer) {
        int len;
        try (FileOutputStream fileOut = new FileOutputStream(subFile)) {
            while ((len = zipInputStream.read(buffer)) > 0) {
                fileOut.write(buffer, 0, len);
            }
        } catch (IOException e) {
            throw new ExceptionConverter(e);
        }
    }

6. itext5进行pdf合并:

  • 本人文件合并后要删除之前的文件,这时需要注意new PdfReader(inputStream)时使用inputStream
  • 不然可能出现:别的程序正在使用而无法删除情况

    /* 合并pdf文件
     * @param files 要合并文件数组(绝对路劲{ "D:\\a.pdf", "D:\\b.pdf" })
     * @param savePath 合并后新产生的文件绝对路径如D:\\temp.pdf
     */
    public static Integer mergePdfFiles(String[] files, String savePath) {
        Document document = null;
        PdfCopy copy = null;
        try (FileOutputStream outputStream = new FileOutputStream(savePath)) {
            // 创建一个与a.pdf相同纸张大小的document
            document = new Document(new PdfReader(files[0]).getPageSize(1));
            copy = new PdfCopy(document, outputStream);
            document.open();
            for (int i = 0; i < files.length; i++) {
                // 一个一个的遍历现有的PDF
                dealFile(files[i], copy, document);
            }
            copy.close();
            document.close();
            return 1;
        } catch (IOException | DocumentException e) {
            LOGGER.info("合并pdf失败,异常信息:{}", e);
        } finally {
            if (document != null) {
                document.close();
            }
            if (copy != null) {
                copy.close();
            }
        }
        return 0;
    }

    private static void dealFile(String file, PdfCopy copy, Document document) {
        PdfReader reader = null;
        try (FileInputStream inputStream = new FileInputStream(file)) {
            reader = new PdfReader(inputStream);
            int n = reader.getNumberOfPages();// PDF文件总共页数
            for (int j = 1; j <= n; j++) {
                document.newPage();
                PdfImportedPage page = copy.getImportedPage(reader, j);
                copy.addPage(page);
            }
            reader.close();
        } catch (IOException | BadPdfFormatException e) {
            throw new ExceptionConverter(e);
        } finally {
            if (reader != null) {
                reader.close();
            }
        }

    }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

itext5创建pdf表格及遇到的一些问题 的相关文章

  • Java8无符号算术

    据广泛报道 Java 8 具有对无符号整数的库支持 然而 似乎没有文章解释如何使用它以及有多少可能 有些函数 例如 Integer CompareUnsigned 很容易找到 并且似乎可以实现人们所期望的功能 但是 我什至无法编写一个简单的
  • 在浏览器中点击应用程序时播放框架挂起

    我正在 Play 中运行一个应用程序activator run 也许 5 次中有 3 次 它会挂起 当我去http localhost 9000 它就永远坐在那里旋转 我看到很多promise timed out错误也 我应该去哪里寻找这个
  • java.io.IOException: %1 不是有效的 Win32 应用程序

    我正在尝试对 XML 文档进行数字签名 为此我有两个选择 有一个由爱沙尼亚认证中心为程序员创建的库 还有一个由银行制作的运行 Java 代码的脚本 如果使用官方 认证中心 库 那么一切都会像魅力一样进行一些调整 但是当涉及到银行脚本时 它会
  • 在 RMarkdown 输出到 PDF 时缩进而不添加项目符号点或编号

    之前有人问过如何在没有项目符号的情况下缩进文本 RMarkdown 中的点 但这是针对 HTML 输出的 在 RMarkdown 中缩进而不添加项目符号点或数字 https stackoverflow com questions 47087
  • java中删除字符串中的特殊字符?

    如何删除字符串中除 之外的特殊字符 现在我用 replaceAll w s 它删除了所有特殊字符 但我想保留 谁能告诉我我该怎么办 Use replaceAll w s 我所做的是将下划线和连字符添加到正则表达式中 我添加了一个 连字符之前
  • 如何将文件透明地传输到浏览器?

    受控环境 IE8 IIS 7 ColdFusion 当从 IE 发出指向媒体文件 例如 mp3 mpeg 等 的 GET 请求时 浏览器将启动关联的应用程序 Window Media Player 我猜测 IIS 提供文件的方式允许应用程序
  • 归并排序中的递归:两次递归调用

    private void mergesort int low int high line 1 if low lt high line 2 int middle low high 2 line 3 mergesort low middle l
  • 如何在 JFreeChart TimeSeries 图表上显示降雨指数和温度?

    目前 我的 TimeSeries 图表每 2 秒显示一个位置的温度 现在 如果我想每2秒显示一次降雨指数和温度 我该如何实现呢 这是我的代码 import testWeatherService TestWeatherTimeLapseSer
  • 使用 AWS Java SDK 为现有 S3 对象设置 Expires 标头

    我正在更新 Amazon S3 存储桶中的现有对象以设置一些元数据 我想设置 HTTPExpires每个对象的标头以更好地处理 HTTP 1 0 客户端 我们正在使用AWS Java SDK http aws amazon com sdkf
  • org.jdesktop.application 包不存在

    几天以来我一直在构建一个 Java 桌面应用程序 一切都很顺利 但是今天 当我打开Netbeans并编译文件时 出现以下编译错误 Compiling 9 source files to C Documents and Settings Ad
  • 使用 Flyway 和 Hibernate 的 hbm2ddl 在应用程序的生命周期中管理数据库模式

    我正在开发 Spring Hibernate MySql 应用程序 该应用程序尚未投入生产 我目前使用 Hibernatehbm2ddl该功能对于管理域上的更改非常方便 我也打算用Flyway用于数据库迁移 在未来的某个时候 该应用程序将首
  • 将 JSON 参数从 java 发布到 sinatra 服务

    我有一个 Android 应用程序发布到我的 sinatra 服务 早些时候 我无法读取 sinatra 服务上的参数 但是 在我将内容类型设置为 x www form urlencoded 之后 我能够看到参数 但不完全是我想要的 我在
  • 当单元格内的 JComboBox 中有 ItemEvent 时,如何获取 CellRow

    我有一个 JTable 其中有一列包含 JComboBox 我有一个附加到 JComboBox 的 ItemListener 它会根据任何更改进行操作 但是 ItemListener 没有获取更改的 ComboBox 所在行的方法 当组合框
  • Android JNI C 简单追加函数

    我想制作一个简单的函数 返回两个字符串的值 基本上 java public native String getAppendedString String name c jstring Java com example hellojni He
  • Java - 不要用 bufferedwriter 覆盖

    我有一个程序可以将人员添加到数组列表中 我想做的是将这些人也添加到文本文件中 但程序会覆盖第一行 因此这些人会被删除 如何告诉编译器在下一个空闲行写入 import java io import java util import javax
  • 如何配置eclipse以保持这种代码格式?

    以下代码来自 playframework 2 0 的示例 Display the dashboard public static Result index return ok dashboard render Project findInv
  • 如何测试 spring-security-oauth2 资源服务器安全性?

    随着 Spring Security 4 的发布改进了对测试的支持 http docs spring io spring security site docs 4 0 x reference htmlsingle test我想更新我当前的
  • 将2-3-4树转换为红黑树

    我正在尝试将 2 3 4 树转换为 java 中的红黑树 但我无法弄清楚它 我将这两个基本类编写如下 以使问题简单明了 但不知道从这里到哪里去 public class TwoThreeFour
  • JAVA - 如何从扫描仪读取文件中检测到“\n”字符

    第一次海报 我在读取文本文件的扫描仪中读取返回字符时遇到问题 正在读取的文本文件如下所示 test txt start 2 0 30 30 1 1 90 30 0 test txt end 第一行 2 表示两个点 第二行 位置索引 0 xp
  • Jackson 将单个项目反序列化到列表中

    我正在尝试使用一项服务 该服务为我提供了一个带有数组字段的实体 id 23233 items name item 1 name item 2 但是 当数组包含单个项目时 将返回该项目本身 而不是包含一个元素的数组 id 43567 item

随机推荐

  • 顺序表的定义及初始化代码实现(C语言)

    适合初学数据结构 不明白如何通过代码实现顺序表 超简洁代码如下 2020 10 16 第一次修改 顺序表结构定义的data是数组类型 应采用静态分配 模糊了静态分配与动态分配 已修改 错误程序L gt data 10 int malloc
  • 报错Description Resource Path Location Type Lifecycle mapping "org.eclipse.m2e.jdt.JarLifecycleMapping

    我这边是因为eclipse想做spring boot项目 因此想安装STS插件 结果装了几个版本 发现都没用 还导致POM XML文件报错 解决问题 1 卸载STS插件 help Install New Software 点击 what i
  • 一个矩阵乘以它本身的转置等于什么

    如果一个矩阵 A 乘以它本身的转置 AT 那么结果就是一个对角矩阵 对角线上的元素就是 A 矩阵中每一列的平方和 其余的元素都是 0 例如 如果 A 矩阵是 a11 a12 a21 a22 那么 A 乘以 AT 就是 a11 2 a21 2
  • 网道 JS教程 (第一天)

    地址 https wangdoc com javascript js 特点 单线程 事件驱动 非阻塞式设计 数据类型 数值 number 整数和小数 比如1和3 14 字符串 string 文本 比如Hello World 布尔值 bool
  • 关闭或者半关闭?!

    2017 05 20 LIBnids这个库 对于关闭的两个状态 理解的不是很清楚 就是 CLOSE算一个状态 CLOSE之前并不调用EXITING的语句 这就很尴尬 目前就当这两个是同一个状态 但是看着有些数据包是关闭的 结果显示不关闭 这
  • 模块学习笔记—(1)编码器减速电机

    模块学习笔记 1 编码器减速电机 编码器电机作用 编码器电机转动可以产生脉冲信号 根据脉冲信号 可以得出轮胎的转动速度 轮胎的位移 电机正反转等 电机介绍 我的编码器电机是130TT减速电机 电机轴转一圈可以产生13个脉冲信号输出 电机减速
  • 使用UUID获得一个不重复的16位账号的算法

    public static String getAccountIdByUUId int machineId 1 最大支持1 9个集群机器部署 int hashCodeV UUID randomUUID toString hashCode i
  • java运行环境

    计算机基础知识 二进制 如图 十进制和二进制的转换 字节 计算机中一个0或者一个1就是一个位 bit 不过并不是最小的数据单位 最下的数据单位是字节 Byte 一个字节等于8个位 计算机中任何数据的存储都是以字节的形式存储 1 B 8 bi
  • 2、线程池篇 - 从理论基础到具体代码示例讲解(持续更新中......)

    前言 暂无 一 线程篇 有关线程部分的知识整理请看我下面这篇博客 1 线程篇 从理论到具体代码案例最全线程知识点梳理 持续更新中 二 线程池基础知识 线程池优点 他的主要特点为 线程复用 管理线程 不需要频繁的创建和销毁线程 控制线程数量
  • html 登录页面 简洁,简单登录html页面

    简单的登录页面 一个简单pc 移动端显示的html codeDocument margin 0px padding 0px bg width 100 height 45vh text align center color fff backg
  • Could not generate command line for the ‘VCCLCompilerTool’ tool

    转载自 http blog csdn net shirui1125 article details 6095774 gt ToolBox error PRJ0004 未能为 VCCLCompilerTool 工具生成命令行 从原有的平台复制
  • AD采集中的10种经典软件滤波程序优缺点分析(附程序)

    在AD采集中经常要用到数字滤波 而不同情况下又有不同的滤波需求 下面是10种经典的软件滤波方法的程序和优缺点分析 1 限幅滤波法 又称程序判断滤波法 2 中位值滤波法 3 算术平均滤波法 4 递推平均滤波法 又称滑动平均滤波法 5 中位值平
  • 自定义协议:如何实现keepalive

    高可用协议招式 keepalive 什么是keepalive tcp如何实现keepalive http如何实现keepalive 自定义协议时该怎样实现keepalive 什么是keepalive Keepalive是一种技术 它可以帮助
  • C语言最简单的服务器和客户端程序

    服务器 include
  • SQLServer之DEFAULT约束

    DEFAULT约束添加规则 1 若在表中定义了默认值约束 用户在插入新的数据行时 如果该行没有指定数据 那么系统将默认值赋给该列 如果我们不设置默认值 系统默认为NULL 2 如果 默认值 字段中的项替换绑定的默认值 以不带圆括号的形式显示
  • shell面试题

    第1章 选择 1 1 退出交互模式的 shell 应键入 A B q C exit D quit 1 2 下列变量名中有效的 shell 变量名是 C 2 time 2 3 trust no 1 2004file 1 3 在 shell 编
  • stm32低功耗解决方案-(外部时钟芯片RX8025T)

    首先在入手一个芯片时要先观看芯片手册rx8025t和rx8025as手册是不一样 两者的寄存器也会有很大的差距 RX8025t中文手册 本文介绍的是一个低功耗解决方案 因为我使用的是stm32的待机模式 所以只需要在唤醒时想办法就行了 因此
  • Android 中的线程池

    Android 中的线程池 线程池的优点 重用线程池中的线程 避免因为线程的创建和销毁所带来的性能开销 能有效控制线程池的最大并发数 避免大量的线程之间因互相抢占系统资源而导致的阻塞现象 能够对线程进行简单管理 并提供定时执行以及指定间隔循
  • C#编程中遇到的一些异常及部分异常的解决方法

    以下内容是在本人在C 编程中遇到的异常 针对部分异常给出了解决办法 但是此解决方法是否真的好用 有待进一步考证 仅供参考 1 System Invalid Operation Exception 类型的未经处理的异常 出现在System W
  • itext5创建pdf表格及遇到的一些问题

    0 核心依赖 1 设置页眉图片及下划线 2 document参数传递 3 生成的pdf文件转base64编码 4 平方 上标显示问题 5 压缩包的文件流InputStream输出文件 6 itext5进行pdf合并 0 核心依赖