需求
有个单据需要打印,单据需要自定义内容展示,单据尺寸、各个模块的布局都是固定的,内容包含文本内容以及Barcode128条形码等,该如何实现?单据部分截图如下:

分析
整个单据包含多个模块,如果用html网页的形式去开发,那么布局开发比较复杂,所以采用iTextPDF + Acrobat 构建动态PDF表单的方式开发。先用Acrobat制作好pdf模板,然后使用iTextPDF框架将数据写入pdf模板后直接打印。
分析下其中的难点以及关键点问题
1、springboot如何整合itextpdf ,需要引入itextpdf 的哪些包?
2、表单中的文本域有横向和纵向排列,如何设置文本域纵向展示?
3、itextpdf 如何生成Barcode128条形码?
4、itextpdf 如何将Barcode128条形码插入pdf表单中?
5、表单中的Barcode128条形码有横向和纵向排列,如何设置Barcode128条形码纵向展示?
实现过程
下面就一步步解决上述问题。
引入itextpdf 相关依赖
1、对于iText 5.x版,需要引入核心库itextpdf和中文字体支持的依赖包itext-asian,如下:
xml
<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、对于iText 7.x版本,引入核心类库itext7-core即可,当前最新版是9.3.0如下。
xml
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>9.3.0</version>
<type>pom</type>
</dependency>
iText 7采用了全新的模块化架构,将功能拆分为多个独立模块,如itext7-core(核心功能)、itext7-layout(高级布局)、itext7-forms(表单处理)等。相比之下,iText 5采用单一架构,功能较为集中,许多模块相互混杂,引入的一些类可能不会被用到。新项目推荐使用iText 7,因为它具有更好的模块化设计和性能优化。
写入表单
1、第二个问题如何设置文本域纵向展示?这个主要是在Acrobat中编辑pdf表单来完成,双击文本域弹出文本域属性输入框->一般->通用属性->方向设置为90度。

2、第3到第5个问题,直接上代码进行解析,代码基于iText 7。
java
/**
* 填充PDF表单并生成新文件
*
* @param templatePath 模板文件路径
* @param outputPath 输出文件路径
* @param formData 表单数据
* @param barcodeData 二维码数据
* @param flattenForm 是否扁平化表单(使字段不可编辑)
* @throws IOException 文件操作异常
*/
public static void fillPdfForm(String templatePath, String outputPath, Map<String, String> formData,Map<String, String> barcodeData,boolean flattenForm) throws IOException {
// 创建PDF读取器和写入器
PdfReader reader = new PdfReader(templatePath);
PdfWriter writer = new PdfWriter(new FileOutputStream(outputPath));
PdfDocument pdfDoc = new PdfDocument(reader, writer);
Document document = new Document(pdfDoc);
// 获取表单对象
PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
// 填充表单数据
for (Map.Entry<String, String> entry : formData.entrySet()) {
String fieldName = entry.getKey();
String fieldValue = entry.getValue();
PdfFormField field = form.getField(fieldName);
if (field != null) {
field.setValue(fieldValue);
} else {
log.info("警告:未找到字段 '" + fieldName + "'");
}
}
//横向条形码设置
// X坐标
float x = 208;
// Y坐标
float y = 546;
// 宽度
float width = 120;
// 高度
float height = 25;
addBarcode(pdfDoc, document, x, y, width, height, barcodeData.get("barcodeData1"), false);
//纵向条形码设置
// X坐标
float x2 = 390;
// Y坐标
float y2 = 520;
// 宽度
float width2 = 120;
// 高度
float height2 = 25;
addBarcode(pdfDoc, document, x2, y2, width2, height2, barcodeData.get("barcodeData2"), true);
// 可选:扁平化表单(使字段成为文档内容的一部分,不可编辑)
if (flattenForm) {
form.flattenFields();
}
// 关闭文档
pdfDoc.close();
document.close();
}
上面这个函数主要对表单进行写入数据,生成一个新的pdf文件主要方便测试查看。生成条形码的的方法如下:
java
/**
* 添加Barcode128条形码
*
* @param pdfDoc pdf文档对象
* @param x 条形码横坐标
* @param y 条形码纵坐标
* @param width 条形码宽度
* @param height 条形码高度
* @param barcodeData 条形码数据
* @param vertical 是否垂直展示
*/
private static void addBarcode(PdfDocument pdfDoc, Document document, float x, float y, float width, float height, String barcodeData, boolean vertical) {
// 创建Barcode128条形码
Barcode128 barcode128 = new Barcode128(pdfDoc);
barcode128.setCode(barcodeData);
// 不显示文本
barcode128.setFont(null);
barcode128.fitWidth(width);
barcode128.setBarHeight(height);
// 将条形码转换为表单XObject
PdfFormXObject barcodeXObject = barcode128.createFormXObject(ColorConstants.BLACK, null, pdfDoc);
// 在指定位置绘制条形码
PdfCanvas canvas = new PdfCanvas(pdfDoc.getFirstPage());
// 添加条形码标签
document.add(new Paragraph(""));
// 旋转90度实现纵向展示
if (vertical) {
// 3. 平移坐标系原点至目标位置
canvas.concatMatrix(1, 0, 0, 1, x, y);
// 4. 应用90度顺时针旋转变换,旋转后,原本水平绘制的条码将变为垂直
canvas.concatMatrix(0, 1, -1, 0, 0, 0);
barcode128.placeBarcode(canvas, null, null);
} else {
// 绘制条形码
canvas.addXObjectAt(barcodeXObject, x, y);
}
}
其中通过new Barcode128(pdfDoc)创建Barcode128条形码对象,横向展示条形码的时候通过
canvas.addXObjectAt(barcodeXObject, x, y) 将条形码插入到pdf表单的指定坐标(x,y)位置。
纵向展示的时候需要将二维码平移坐标系原点至目标位置,然后90度顺时针旋转变换,关键函数:
java
public PdfCanvas concatMatrix(double a, double b, double c, double d, double e, double f) {
...
}
方法中的六个参数共同定义了一个用于图形变换的 3×3 矩阵,各参数具体作用如下:
参数 a:控制图形在 X 轴方向的缩放比例。
参数 b:控制图形在水平方向的倾斜程度。
参数 c:控制图形在垂直方向的倾斜程度。
参数 d:控制图形在 Y 轴方向的缩放比例。
参数 e:指定图形在 X 轴方向的平移距离。
参数 f:指定图形在 Y 轴方向的平移距离。
测试
编写main函数进行测试。
java
public static void main(String[] args) {
try {
// 准备表单数据
Map<String, String> formData = new HashMap<>();
formData.put("orderNo", "*77582587758258");
formData.put("position", "400B ");
formData.put("position_no", "C262-11 C3");
//其他省略
Map<String, String> barcodeData = new HashMap<>();
barcodeData.put("barcodeData1","PROD-2025-001");
barcodeData.put("barcodeData2","PROD-2025-002");
// 填充表单并生成新文件
fillPdfForm("C:\\Users\\user\\Desktop\\order.pdf", "new_order.pdf", formData,barcodeData,true);
log.info("PDF表单填充完成,已生成新文件:new_order.pdf");
} catch (IOException e) {
log.error("处理PDF时发生错误:",e);
}
}