使用PDFBox为PDF表单字段添加计算脚本及全局JS函数咨询
实现方案
要实现JavaScript函数全局复用,只需要将公共函数写入文档级JavaScript名称树即可,PDF文档打开时会自动执行该名称树下的所有脚本,函数会被注册到全局上下文,所有字段的事件脚本都可以直接调用。
具体实现代码
1. 全局JS逻辑(可单独存为文件也可以硬编码)
// 全局通用计算函数,所有字段事件均可直接调用 function calculateValue(sourceFieldName, targetFieldName) { const sourceVal = this.getField(sourceFieldName).value; // 增加非空、数值合法性判断,避免报错 if (sourceVal !== null && !isNaN(Number(sourceVal))) { this.getField(targetFieldName).value = Math.floor(Number(sourceVal) / 2 - 5); } }
2. Java端集成代码
try (var document = PDDocument.load(pdfFile)) { var catalog = document.getDocumentCatalog(); var acroForm = catalog.getAcroForm(); // ========== 添加全局公共JS函数 ========== // 读取全局JS文件内容,也可以直接写字符串 String globalJsContent = FileUtils.readFileToString(globalJsFile, StandardCharsets.UTF_8); PDActionJavaScript globalJsAction = new PDActionJavaScript(globalJsContent); // 初始化文档名称字典 PDDocumentNameDictionary nameDict = catalog.getNames(); if (nameDict == null) { nameDict = new PDDocumentNameDictionary(catalog); catalog.setNames(nameDict); } // 初始化JavaScript名称树 PDJavascriptNameTreeNode jsNameTree = nameDict.getJavaScript(); if (jsNameTree == null) { jsNameTree = new PDJavascriptNameTreeNode(); nameDict.setJavaScript(jsNameTree); } // 将全局JS加入名称树,key自定义不重复即可 jsNameTree.addEntry("commonCalculateFunction", globalJsAction); // ========== 给多个字段绑定事件,直接调用全局函数 ========== // 示例1:fieldA变更时更新fieldB PDFormFieldAdditionalActions fieldAActions = new PDFormFieldAdditionalActions(); fieldAActions.setC(new PDActionJavaScript("calculateValue('fieldA', 'fieldB');")); PDTextField fieldA = (PDTextField) acroForm.getField("fieldA"); fieldA.setActions(fieldAActions); // 示例2:fieldC变更时更新fieldD PDFormFieldAdditionalActions fieldCActions = new PDFormFieldAdditionalActions(); fieldCActions.setC(new PDActionJavaScript("calculateValue('fieldC', 'fieldD');")); PDTextField fieldC = (PDTextField) acroForm.getField("fieldC"); fieldC.setActions(fieldCActions); // 更新计算顺序数组 COSArray calculateOrder = new COSArray(); calculateOrder.add(fieldA); calculateOrder.add(fieldC); acroForm.getCOSObject().setItem(COSName.CO, calculateOrder); document.save(pdfFile); } catch (IOException e) { e.printStackTrace(); }
注意事项
- 全局JS的自定义key不能重复,否则会覆盖同key的已有脚本
- 所有在全局JS中定义的函数、变量,都会挂载到文档对象上下文,所有JS执行环境都可以直接访问
- 如果需要新增其他全局公共函数,只需要追加到全局JS内容中,或者新增一个名称树条目即可
内容的提问来源于stack exchange,提问作者MaikB
相关产品推荐
相关产品推荐

