5. 插件机制(Plugin mechanism)

插件机制是poi-tl的核心,默认的五大內建模板语法是通过插件方式加载的。插件的核心逻辑是在模板的基础上通过poi-tl和poi提供的API操作word文档,实现插件就是实现自己的渲染策略。

由于需要操作Word文档,我们需要掌握一些Apache POI API的知识,可以参见Apache官方API,这里也有一个快速入门的教程:Apache POI Word(docx) 入门示例教程。如果你写了一个不错的插件,欢迎提交Pull Request。

5.1. 新增RenderPolicy策略

內建策略是poi-tl自带的一些渲染策略,用来处理文本、图片、列表、表格、文档合并等:

  • TextRenderPolicy

  • PictureRenderPolicy

  • NumbericRenderPolicy

  • MiniTableRenderPolicy

  • DocxRenderPolicy

我们可以通过实现 RenderPolicy 接口扩展自己的渲染策略:

  1. public interface RenderPolicy {
  2. void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template); (1) (2) (3)
  3. }
1ElementTemplate是当前模板标签所在位置
2data是数据模型
3通过XWPFTemplate获得Apache POI增强类NiceXWPFDocument,继而可以在当前模板标签位置插入段落,图片,表格等
原则上Apache POI支持的操作,都可以在当前模板位置进行渲染。

示例:我们创建一个自己的表格渲染策略CustomTableRenderPolicy,使用表格API来操作表格,doc.insertNewTable() 是在当前模板位置插入表格,正如可以实现任何渲染逻辑一样,我们可以随心所欲的操作表格了。

AbstractRenderPolicy是一个抽象模板类,定义了一些骨架步骤并且将数据模型的校验和渲染逻辑分开,新的策略继承AbstractRenderPolicy类不是必须的。

  1. public class CustomTableRenderPolicy extends AbstractRenderPolicy<Object> {
  2. @Override
  3. protected void afterRender(RenderContext context) {
  4. // 清空模板标签所在段落
  5. clearPlaceholder(context, true);
  6. }
  7. @Override
  8. public void doRender(RunTemplate runTemplate, Object data, XWPFTemplate template)
  9. throws Exception {
  10. NiceXWPFDocument doc = template.getXWPFDocument();
  11. XWPFRun run = runTemplate.getRun();
  12. // 定义行列
  13. int row = 10, col = 8;
  14. // 插入表格
  15. XWPFTable table = doc.insertNewTable(run, row, col);
  16. // 定义表格宽度、边框和样式
  17. TableTools.widthTable(table, MiniTableRenderData.WIDTH_A4_FULL, col);
  18. TableTools.borderTable(table, 4);
  19. // 调用XWPFTable API操作表格:data对象可以包含任意你想要的数据,包括图片文本等
  20. // 调用MiniTableRenderPolicy.Helper.renderRow方法快速方便的渲染一行数据
  21. // 调用TableTools类方法操作表格,比如合并单元格
  22. // ......
  23. TableTools.mergeCellsHorizonal(table, 0, 0, 7);
  24. TableTools.mergeCellsVertically(table, 0, 1, 9);
  25. }
  26. }

5.2. 自定义模板策略

所有的插件都是通过如下构建器来配置:

  1. ConfigureBuilder builder = Configure.newBuilder();
  2. XWPFTemplate.compile("~/template.docx", builder.buid());

当我们有个模板标签为{{report}},它本身是一个文本模板,如果希望在这个位置做些不一样或者更复杂的事情,我们可以通过构建器设定模板的渲染策略:

  1. builder.customPolicy("report", new MyRenderPolicy());

5.3. 新增语法插件

比如增加%语法:{{%var}},对应自定义的渲染策略 PercentRenderPolicy,加载插件代码如下:

  1. builder.addPlugin('%', new PercentRenderPolicy());

由于內建模板也是通过插件方式加载的,我们甚至可以改变它们的语法:

  1. builder.addPlugin('@', new MiniTableRenderPolicy());
  2. builder.addPlugin('#', new PictureRenderPolicy());

这样{{@var}}就变成了表格模板,{{#var}}变成了图片模板,虽然不建议改变內建模板,但是从中可以看到poi-tl插件的设计思想,深藏功与名。

5.4. Helper辅助类

在內建策略中,通常会提供一个静态Helper辅助类,在我们实现自己的RenderPolicy时,也可以通过这些辅助类操作文档。

  1. // 某个位置渲染文本
  2. TextRenderPolicy.Helper.renderTextRun(XWPFRun, Object);
  3. // 某个位置渲染图片
  4. PictureRenderPolicy.Helper.renderPicture(XWPFRun, PictureRenderData);
  5. // 某个位置渲染列表
  6. NumbericRenderPolicy.Helper.renderNumberic(XWPFRun, NumbericRenderData);
  7. // 渲染表格的一行数据
  8. MiniTableRenderPolicy.Helper.renderRow(XWPFTable, int, RowRenderData);
  9. // 渲染单元格
  10. MiniTableRenderPolicy.Helper.renderCell(XWPFTableCell, CellRenderData, TableStyle)