04 March 2022

Jxls 模板里的自定义函数,可以用来格式化日期、金额或执行少量展示计算。升级后如果函数突然找不到,需要先检查表达式引擎的命名空间配置,而不是立即修改所有模板。

变化发生在 JEXL 引擎配置

下面对应使用 Apache Commons JEXL 的两种 API 形态。具体写法由项目实际使用的 Jxls evaluator 和 JEXL 主版本决定,不能把它们简单理解为任何 Jxls 新旧版本都能直接互换。

使用 JEXL 2 API 的配置片段:

Map<String, Object> funcs = new HashMap<>();
funcs.put("utils", new ExcelFunction());
evaluator.getJexlEngine().setFunctions(funcs);

使用 JEXL 3 的 JexlBuilder 时,命名空间在构建引擎时提供:

Map<String, Object> funcs = new HashMap<>();
funcs.put("utils", new ExcelFunction());
JexlEngine engine = new JexlBuilder().namespaces(funcs).create();
evaluator.setJexlEngine(engine);

这里的 evaluator 必须是对应版本暴露这些方法的实现,ExcelFunction 是应用提供的函数类。JEXL 2 与 3 的类包名不同,运行包中也要避免混入与编译时不一致的依赖。较新的 Jxls 可能提供自己的 builder 配置入口,应按所用主版本文档接入。

函数名称和模板一起检查

模板通过 utils 命名空间调用函数,因此映射中的键不能随意改名。函数应使用清楚的 public 方法签名,避免过多重载造成解析歧义。金额优先使用 BigDecimal,并显式指定舍入规则;日期格式化也应约定时区。

只注册模板真正需要的函数,不要把整个业务服务或有副作用的对象暴露给表达式引擎。模板来源、引擎权限和函数可访问范围同样属于运行条件。

验证要落到生成的工作簿

准备一个最小模板和固定数据,验证普通值、空值、异常输入及函数调用失败的表现。生成后重新读取单元格,检查值、类型和格式:显示为日期字符串与真正的日期单元格,不是同一种结果。

最后确认自定义引擎是在模板执行前配置完成,而且确实被转换过程使用。只调用了配置方法但没有接入实际转换器,模板仍然会报找不到函数。

参考:Apache Commons JEXL、Jxls 项目。





blog comments powered by Disqus
Fork me on GitHub