目录
依赖
XML
<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>
创建单元格
java
/**
* 创建单元格
*
* @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;
}
表格数据行辅助添加方法
java
/**
* 辅助添加表格数据行
* @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));
}
java
/**
* 辅助添加表格行数据
* @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));
}
}
}
创建表格表头
java
/**
* 创建表头单元格
*
* @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);
}
创建下划线
java
/**
* 创建下划线
*
* @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;
}
java
/**
* 使用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() {
@Override
public 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;
}
创建带下划线的文字
java
/**
* 创建带下划线的文字块
* @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写入器
java
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();
设置字体,避免中文不显示问题
java
// 字体,中文字体,避免文字不显示
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);// 页脚字体
标题、副标题定义
java
// 标题
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);
正文段落
java
// 添加内容段落
Paragraph content = new Paragraph();
content.setAlignment(Element.ALIGN_JUSTIFIED); // 段落两端对齐
content.add(new Chunk("風華絕代、風流倜儻、玉樹臨風", contentFont));
content.add(Chunk.NEWLINE);// 换行,两个效果为空一行
content.add(Chunk.NEWLINE);
正文中添加带下划线的文字
java
content.add(createUnderlinedText(text,contentFont));// 正文添加带下划线的文字,需这样单独添加
表格------创建表格
java
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 行作为表头,跨页时重复
表格------创建表头-上面的方法
java
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 方法
表格------创建单元格-上面的方法
java
addTableRow(table, "絕代風華", "1956-09-12", "Cheung Kwok Wing", contentFont);// 添加表格数据,几行就几个 addTableRow 方法
添加页脚
java
// 添加页脚
Paragraph footer = new Paragraph("【风华绝代】", footerFont);
footer.setAlignment(Element.ALIGN_CENTER);
document.add(footer);
添加图片
java
// 添加图片(可选)
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());
}
关闭文档
java
document.close();// 关闭文档
页码处理类
java
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);
}
@Override
public void onOpenDocument(PdfWriter writer, Document document) {
totalPagesTemplate = writer.getDirectContent().createTemplate(30, 17);// 创建用于总页数的模板
}
@Override
public 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();
}
/**
* 文档关闭时,写入总页数到模板
*/
@Override
public 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 随笔