【pdf】Java代码生成PDF

目录

依赖

创建单元格

表格数据行辅助添加方法

创建表头单元格

创建下划线

创建带下划线的文字

创建PDF


依赖

<dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.4.2</version>
</dependency>
<dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.13</version>
</dependency>
<dependency><groupId>com.itextpdf</groupId><artifactId>itext-asian</artifactId><version>5.2.0</version>
</dependency>

创建单元格

    /*** 创建单元格** @param text            显示值* @param font            字体* @param horizontalAlign 值水平显示位置(例:Element.ALIGN_CENTER => 居中)* @param verticalAlign   值垂直显示位置(例:Element.ALIGN_MIDDLE => 居中)* @param minHeight       最小行高* @return PdfPCell*/private static PdfPCell createCell(String text, Font font, int horizontalAlign, int verticalAlign, float minHeight) {Paragraph para = new Paragraph(text, font);para.setAlignment(horizontalAlign);para.setLeading(para.getLeading() * 1.2f);PdfPCell cell = new PdfPCell(para);cell.setHorizontalAlignment(horizontalAlign);// 水平居中cell.setVerticalAlignment(verticalAlign);// 垂直居中cell.setMinimumHeight(minHeight);  // 设置最小高度
//        cell.setPadding(0);// 内边距cell.setBorderWidth(0.5f);// 单元格边框宽度cell.setNoWrap(false);// 自动换行return cell;}

表格数据行辅助添加方法

    /*** 辅助添加表格数据行* @param table     表格* @param col1      列1值* @param col2      列2值* @param col3      列3值* @param font      字体*/private static void addTableRow(PdfPTable table, String col1, String col2, String col3, Font font) {// 有几列几个 table.addCell 方法table.addCell(createCell(col1, font, Element.ALIGN_CENTER, Element.ALIGN_MIDDLE, 25f));table.addCell(createCell(col2, font, Element.ALIGN_CENTER, Element.ALIGN_MIDDLE, 25f));table.addCell(createCell(col3, font, Element.ALIGN_CENTER, Element.ALIGN_MIDDLE, 25f));}
    /*** 辅助添加表格行数据* @param table                 表格* @param tableHeaderNumber     表格表头列数* @param font                  字体* @param horizontalAlign       值水平显示位置(例:Element.ALIGN_CENTER => 居中)* @param verticalAlign         值垂直显示位置(例:Element.ALIGN_MIDDLE => 居中)* @param minHeight             最小行高* @param column                单元格数据,x列传入x个使用【,】隔开*/private static void addTableRow(PdfPTable table,int tableHeaderNumber, Font font, int horizontalAlign, int verticalAlign, float minHeight, String... column) {if (column.length == 1 && column[0].isEmpty()) {// 只传入一个【""】值if (tableHeaderNumber > 0) {// 表头列数 <= 0 时,不创建空行数据for (int i = 0; i < tableHeaderNumber; i++) {// 根据表头列数生成对应的空行数据,值为【" "】(为""时不会创建空行数据)table.addCell(createCell(" ", font, horizontalAlign, verticalAlign, minHeight));}}}else {for (String s : column) {table.addCell(createCell(s, font, horizontalAlign, verticalAlign, minHeight));}}}

创建表格表头

    /*** 创建表头单元格** @param table           表* @param text            显示值* @param font            字体* @param bgColor         单元格背景色* @param horizontalAlign 值水平显示位置(例:Element.ALIGN_CENTER => 居中)* @param verticalAlign   值垂直显示位置(例:Element.ALIGN_MIDDLE => 居中)* @param height          行高*/private static void createTableHeader(PdfPTable table, String text, Font font, BaseColor bgColor, int horizontalAlign, int verticalAlign, float height) {Paragraph para = new Paragraph(text, font);para.setAlignment(horizontalAlign);PdfPCell cell = new PdfPCell(para);cell.setBackgroundColor(bgColor);cell.setHorizontalAlignment(horizontalAlign);// 水平居中cell.setVerticalAlignment(verticalAlign);// 垂直居中cell.setMinimumHeight(height);  // 设置最小高度cell.setBorderWidth(0.5f);// 单元格边框宽度
//        cell.setFixedHeight(height);  // 固定行高,文字超出高度不会显示
//        cell.setPadding(8);// 内边距
//        cell.setNoWrap(false);// 自动换行table.addCell(cell);}

创建下划线

    /*** 创建下划线** @param width 宽* @param font  字体* @return Chunk*/private static Chunk createUnderlineChunk(float width, Font font) {Chunk underlineChunk = new Chunk(" ");underlineChunk.setHorizontalScaling(width); // 设置宽度underlineChunk.setUnderline(0.5f, -1f);// param-1:线宽 param-2:线位置,基于行底部,负数下调正数上调underlineChunk.setFont(font);// 设置字体return underlineChunk;}
    /*** 使用PdfContentByte自定义绘制下划线** @param writer PdfWriter* @param width  宽度* @return Chunk*/private static Chunk createCustomDrawnLine(PdfWriter writer, float width) {// 创建一个空白Chunk作为占位符Chunk placeholder = new Chunk(" ");// 添加自定义绘制功能placeholder.setGenericTag(" ");writer.setPageEvent(new PdfPageEventHelper() {@Overridepublic void onGenericTag(PdfWriter writer, Document document,Rectangle rect, String text) {// 获取画布PdfContentByte canvas = writer.getDirectContent();canvas.saveState();// 设置下划线样式canvas.setLineWidth(0.5f);canvas.setColorStroke(BaseColor.BLACK);// 计算下划线位置float y = rect.getBottom() - 3; // 在文本下方3点处float x1 = rect.getLeft();float x2 = x1 + width;// 绘制下划线canvas.moveTo(x1, y);canvas.lineTo(x2, y);canvas.stroke();canvas.restoreState();}});return placeholder;}

创建带下划线的文字

    /*** 创建带下划线的文字块* @param text      文字* @param font      字体* @return          Chunk*/private static Chunk createUnderlinedText(String text, Font font){Chunk textChunk = new Chunk(text, font);textChunk.setUnderline(0.5f, -1f);// 设置下划线:线宽0.5,位置在基线下方1点return textChunk;}

创建PDF

创建 Document 对象、pdf写入器

        Document document = new Document(PageSize.A4, 90, 90, 80, 50);// 创建文档对象(A4纸大小,边距:左, 右, 上, 下)PdfWriter writer = PdfWriter.getInstance(document, Files.newOutputStream(Paths.get(dest)));// 创建PDF写入器
//        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));PageNumberEventHandler eventHandler = new PageNumberEventHandler();writer.setPageEvent(eventHandler);// 打开文档document.open();

设置字体,避免中文不显示问题

        // 字体,中文字体,避免文字不显示BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);Font titleFont = new Font(baseFont, 18, Font.BOLD);// 标题字体Font subtitleFont = new Font(baseFont, 12);// 副标题字体Font contentFont = new Font(baseFont, 12);// 正文字体Font headerFont = new Font(baseFont, 12);// 表头字体Font footerFont = new Font(baseFont, 12);// 页脚字体

标题、副标题定义 

        // 标题Paragraph title = new Paragraph("Leslie Lee", titleFont);title.setAlignment(Element.ALIGN_CENTER);// 左右居中title.setSpacingAfter(5f); // 设置段后间距document.add(title);// 副标题Paragraph subtitle = new Paragraph("(風華絕代)", subtitleFont);subtitle.setAlignment(Element.ALIGN_CENTER);subtitle.setSpacingAfter(25f);document.add(subtitle);

 正文段落

        // 添加内容段落Paragraph content = new Paragraph();content.setAlignment(Element.ALIGN_JUSTIFIED); // 段落两端对齐content.add(new Chunk("風華絕代、風流倜儻、玉樹臨風", contentFont));content.add(Chunk.NEWLINE);// 换行,两个效果为空一行content.add(Chunk.NEWLINE);

 正文中添加带下划线的文字

        content.add(createUnderlinedText(text,contentFont));// 正文添加带下划线的文字,需这样单独添加

表格——创建表格

        PdfPTable table = new PdfPTable(3);// 创建表格 x列table.setWidthPercentage(100); // 表格宽度占页面百分比table.setSpacingBefore(5f);  // 表格前间距table.setSpacingAfter(10f);   // 表格后间距table.setSplitLate(false); // 防止单元格在分页时被拆分table.setSplitRows(true);  // 允许行拆分
//        table.setHeaderRows(1); // 前 x 行作为表头,跨页时重复

表格——创建表头-上面的方法

        addTableHeader(table, "代表作", headerFont, null, Element.ALIGN_CENTER, Element.ALIGN_MIDDLE, 25f);// 添加表头单元格,几列就几个 addTableHeader 方法addTableHeader(table, "时间", headerFont, null, Element.ALIGN_CENTER, Element.ALIGN_MIDDLE, 25f);// 添加表头单元格,几列就几个 addTableHeader 方法addTableHeader(table, "角色", headerFont, null, Element.ALIGN_CENTER, Element.ALIGN_MIDDLE, 25f);// 添加表头单元格,几列就几个 addTableHeader 方法

 表格——创建单元格-上面的方法

        addTableRow(table, "絕代風華", "1956-09-12", "Cheung Kwok Wing", contentFont);// 添加表格数据,几行就几个 addTableRow 方法

 添加页脚

        // 添加页脚Paragraph footer = new Paragraph("【风华绝代】", footerFont);footer.setAlignment(Element.ALIGN_CENTER);document.add(footer);

 添加图片

        // 添加图片(可选)try {String imagePath = "img.jpg"; // 替换为实际图片路径Image img = Image.getInstance(imagePath);img.scaleToFit(100, 100); // 调整图片大小img.setAbsolutePosition(36, 36); // 左下角位置document.add(img);} catch (Exception e) {System.err.println("图片添加失败: " + e.getMessage());}

 关闭文档

        document.close();// 关闭文档

 页码处理类

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;import java.io.IOException;/**     页码处理* @author Leslie Lee* @version 2003/04/01* @date 1956/09/12*/
public class PageNumberEventHandler extends PdfPageEventHelper {private final Font footerFont;// 页脚字体private PdfTemplate totalPagesTemplate;// 用于存储总页数的模板private final BaseFont baseFont;// 基础字体public PageNumberEventHandler() throws DocumentException, IOException {super();baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);footerFont = new Font(baseFont, 10, Font.NORMAL, BaseColor.DARK_GRAY);}@Overridepublic void onOpenDocument(PdfWriter writer, Document document) {totalPagesTemplate = writer.getDirectContent().createTemplate(30, 17);// 创建用于总页数的模板}@Overridepublic void onEndPage(PdfWriter writer, Document document) {PdfContentByte canvas = writer.getDirectContent();// 获取PDF内容canvas.saveState();// 保存当前状态// 创建页码文本String footerText = writer.getPageNumber() + " /";// 当前页码// 设置页脚位置(居中底部)float x = (document.left() + document.right()) / 2;// 文档中间位置float y = document.bottom() - 20;// 文档底部上移 20 的位置ColumnText.showTextAligned(canvas, Element.ALIGN_CENTER, new Phrase(footerText, footerFont), x, y, 0);// 添加页码文本float pageTextWidth = baseFont.getWidthPoint(footerText, 9);// 计算页码文本宽度// 添加总页数模板(占位符)canvas.addTemplate(totalPagesTemplate, x + pageTextWidth / 2 + 3, y);  // 计算位置 x为左右位置(数大越右、数小越左) y为垂直位置(减数为下调、加数为上调)// 添加"页"字
//            canvas.beginText();
//            canvas.setFontAndSize(baseFont, 9);
//            canvas.setColorFill(BaseColor.DARK_GRAY);
//            canvas.showTextAligned(Element.ALIGN_CENTER, "页", x + pageTextWidth / 2 + 22, y, 0);
//            canvas.endText();// 添加页码左标题
//            String titleText = "";
//            ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, new Phrase(titleText, footerFont), document.left(), y, 0);// 添加页码右标题
//            String companyText = "";
//            ColumnText.showTextAligned(canvas, Element.ALIGN_RIGHT, new Phrase(companyText, footerFont), document.right(), y, 0);// 添加页脚分隔线
//            canvas.setLineWidth(0.5f);// 分隔线粗细
//            canvas.setColorStroke(BaseColor.LIGHT_GRAY);// 灰色
//            canvas.moveTo(document.left(), y + 10);// 坐标起点  参数1:开始位置(左右) 参数2:高度(上下) 正数上调负数下调
//            canvas.lineTo(document.right(), y + 10);// 坐标终点 参数1:结束位置(左右) 参数2:高度(上下) 正数上调负数下调
//            canvas.stroke();// 恢复状态canvas.restoreState();}/*** 文档关闭时,写入总页数到模板*/@Overridepublic void onCloseDocument(PdfWriter writer, Document document) {totalPagesTemplate.beginText();totalPagesTemplate.setFontAndSize(baseFont, 10);totalPagesTemplate.setColorFill(BaseColor.DARK_GRAY);totalPagesTemplate.showText(String.valueOf(writer.getPageNumber())); // 有几页封面就减几,没有封面不减totalPagesTemplate.endText();}
}

                                                                Leslie Lee 随笔

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

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

相关文章

Vite 的“心脏移植”:Rolldown

1. 现状&#xff1a;你搁这儿玩双截棍呢&#xff1f; 现在Vite这逼样&#xff1a;开发用esbuild&#xff0c;生产用Rollup&#xff0c;精分现场是吧&#xff1f;大型项目尼玛启动慢成狗&#xff0c;请求多到炸穿地心&#xff0c;生产/dev环境差异能让你debug到原地升天&#x…

【网络安全】文件上传型XSS攻击解析

引言 文件上传功能作为现代Web应用的核心交互模块&#xff0c;其安全防护水平直接关系到系统的整体安全性。本文基于OWASP、CVE等权威研究&#xff0c;结合2024-2025年最新漏洞案例&#xff0c;系统剖析了文件上传场景下的XSS攻击技术演进路径。研究揭示&#xff1a;云原生架构…

Java 集合框架底层数据结构实现深度解析

Java 集合框架&#xff08;Java Collections Framework, JCF&#xff09;是支撑高效数据处理的核心组件&#xff0c;其底层数据结构的设计直接影响性能与适用场景。本文从线性集合、集合、映射三大体系出发&#xff0c;系统解析ArrayList、LinkedList、HashMap、TreeSet等核心类…

Dify动手实战教程(进阶-知识库:新生入学指南)

目录 进阶-知识库&#xff1a;新生入学指南 1.创建知识库 2.创建Agent 去年agent智能体爆火&#xff0c;我自己也使用了多款智能体产品来搭建agent解决生活中的实际问题&#xff0c;如dify、coze等等。dify作为一个开源的框架得到了大量的应用&#xff0c;如一些需要隐私保护…

Vue3+TypeScript+ Element Plus 从Excel文件导入数据,无后端(点击按钮,选择Excel文件,由前端解析数据)

在 Vue 3 TypeScript Element Plus 中实现文件导入功能&#xff0c;可以通过以下步骤完成&#xff1a; 1. 安装依赖 bash 复制 下载 npm install xlsx # 用于解析Excel文件 npm install types/xlsx -D # TypeScript类型声明 2. 组件实现 vue 复制 下载 <templ…

一些torch函数用法总结

1.torch.nonzero(input, *, as_tupleFalse) 作用&#xff1a;在PyTorch中用于返回输入张量中非零元素的位置索引。 返回值&#xff1a;返回一个张量&#xff0c;每行代表一个非零元素的索引。 参数含义&#xff1a; &#xff08;1&#xff09;input:输入的PyTorch 张量。 …

moments_object_model_3d这么理解

这篇文章是我对这个算子的理解,和三个输出结果分别用在什么地方 算子本身 moments_object_model_3d( : : ObjectModel3D, MomentsToCalculate : Moments) MomentsToCalculate:对应三个可选参数,分别是 1, mean_points: 就是点云在xyz方向上坐标的平均值 2, central_m…

性能测试|数据说话!在SimForge平台上用OpenRadioss进行汽车碰撞仿真,究竟多省时?

Radioss是碰撞仿真领域中十分成熟的有限元仿真软件&#xff0c;可以对工程中许多非线性问题进行求解&#xff0c;例如汽车碰撞、产品跌落、导弹爆炸、流固耦合分析等等。不仅可以提升产品的刚度、强度、碰撞的安全性能等&#xff0c;还可以在降低产品研发成本的同时提升研发效率…

数据结构学习——KMP算法

//KMP算法 #include <iostream> #include <string> #include <vector> #include <cstdlib>using namespace std;//next数组值的推导void getNext(string &str, vector<int>& next){int strlong str.size();//next数组的0位为0next[0]0;…

博士,超28岁,出局!

近日&#xff0c;长沙市望城区《2025年事业引才博士公开引进公告》引发轩然大波——博士岗位年龄要求28周岁及以下&#xff0c;特别优秀者也仅放宽至30周岁。 图源&#xff1a;网络 这份规定让众多"高龄"博士生直呼不合理&#xff0c;并在社交平台掀起激烈讨论。 图源…

使用Nuitka打包Python程序,编译为C提高执行效率

在 Python 的世界里&#xff0c;代码打包与发布一直是开发者关注的重要话题。前面我们介绍了Pyinstaller的使用&#xff0c;尽管 PyInstaller 是最常用的工具之一&#xff0c;但对于性能、安全性、兼容性有更高要求的项目&#xff0c;Nuitka 正迅速成为更优的选择。本文将全面介…

基于机器学习的恶意请求检测

好久没写文章了&#xff0c;忙毕业设计ING&#xff0c;终于做好了发出来。 做了针对恶意URL的检测&#xff0c;改进了杨老师这篇参考文献的恶意请求检测的方法 [网络安全自学篇] 二十三.基于机器学习的恶意请求识别及安全领域中的机器学习-CSDN博客 选择使用了XGBoost算法进…

深入理解XGBoost(何龙 著)学习笔记(五)

深入理解XGBoost&#xff08;何龙 著&#xff09;学习笔记&#xff08;五&#xff09; 本文接上一篇&#xff0c;内容为线性回归&#xff0c;介绍三部分&#xff0c;首先介绍了"模型评估”&#xff0c;然后分别提供了线性回归的模型代码&#xff1a;scikit-learn的Linear…

工业级MySQL基准测试专家指南

工业级MySQL基准测试专家指南 一、深度风险识别增强版 风险类型典型表现进阶检测方案K8s存储性能抖动PVC卷IOPS骤降50%使用kubestone进行CSI驱动压力测试HTAP读写冲突OLAP查询导致OLTP事务超时用TPCH+Sysbench混合负载测试冷热数据分层失效压缩表查询耗时激增10倍监控INNODB_C…

Spring WebFlux和Spring MVC的对比

原文网址&#xff1a;Spring WebFlux和Spring MVC的对比-CSDN博客 简介 本文介绍Spring WebFlux和Spring MVC的区别。 Webflux&#xff1a;是异步非阻塞的&#xff08;IO多路复用&#xff09;&#xff0c;基于Netty。适合网络转发类的应用&#xff0c;比如&#xff1a;网关。…

解析401 Token过期自动刷新机制:Kotlin全栈实现指南

在现代Web应用中&#xff0c;Token过期导致的401错误是影响用户体验的关键问题。本文将手把手实现一套完整的Token自动刷新机制&#xff0c;覆盖从原理到实战的全过程。 一、为什么需要Token自动刷新&#xff1f; 当用户使用应用时&#xff0c;会遇到两种典型场景&#xff1a;…

《解构线性数据结构的核心骨架:从存储模型到操作范式的深度解析》

线性数据结构概述 线性数据结构是数据元素按线性顺序排列的集合,每个元素有唯一的前驱和后继(除首尾元素)。常见类型包括数组、队列、链表和栈,每种结构在存储和操作上具有独特特性。 线性表:顾名思义,线性表就是数据排成像一条线的结构。每个线性表上的数据最多只有前和后…

HW蓝队工作流程

HW蓝队工作流程 由多领域安全专家组成攻击队&#xff0c;在保障业务系统安全的前提下&#xff0c;直接在真实网络环境开展对抗&#xff0c;对参演单位目标系进行可控、可审计的网络安全实战攻击&#xff0c;通过攻防演习检验参演单位的安全防护和应急处置能力&#xff0c;提高…

语音相关-浏览器的自动播放策略研究和websocket研究

策略详情 媒体参与度 AudioContext音频API的实现 new Audio音频API的实现 相关实践 网页端 使用new Audio创建的音频对象进行音频播放的时候&#xff0c;如果用户没有与页面进行交互&#xff0c;那么会报错如下&#xff1a; 使用AudioContext创建的对象播放音频&#xff0c;…

Linux操作系统网络服务模块一DHCP服务概述

前言&#xff1a; 在Linux网络服务体系架构中&#xff0c;​DHCP&#xff08;Dynamic Host Configuration Protocol&#xff09;​​ 作为核心服务之一&#xff0c;承担着局域网内主机网络参数动态分配的关键任务。其设计初衷是解决传统手动配置IP地址的效率瓶颈与错误风…