SpringBoot + iTextPDF + Acrobat 构建动态PDF表单的完整实践
需求
有个单据需要打印,单据需要自定义内容展示,单据尺寸、各个模块的布局都是固定的,内容包含文本内容以及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,如下:
<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如下。
<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。
/*** 填充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文件主要方便测试查看。生成条形码的的方法如下:
/*** 添加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);// 将条形码转换为表单XObjectPdfFormXObject 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度顺时针旋转变换,关键函数:
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函数进行测试。
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);}}
