poi操作表格table

时间:2022-09-16 23:09:41

转载,原文地址:
https://github.com/Sayi/sayi.github.com/issues/21

表格对于页面的布局具有重大的意义,正因为其灵活性,所以用模板引擎处理word中的Table时,显得并不是那么简单,本文将讨论如何利用poi-tl(1.2.0版本)提供的工具来简化表格处理。关于如何使用poi-tl,参见中文Wiki

表格模板

poi-tl默认实现了N行N列的样式(如下图),同时提供了当数据为空时,展示一行空数据的文案(如下图中的No Data Descs)。
poi操作表格table

在poi-tl的1.2.0版本中,表格模板语法是#,数据结构是com.deepoove.poi.data.TableRenderData。
1. 表格头使用headers[]定义,支持设置背景色
2. 表格数据使用datas[]定义,不同列的数据在datas中使用分号隔开
3. 宽度使用width定义
4. 无数据文案使用noDatadesc定义

{
  "datas": [ "beijing;beijing", "zhejiang;hangzhou" ],
  "headers": [ { "style": { "color": "1E915D", "fontSize": 0 }, "text": "province" }, { "style": { "color": "1E915D", "fontSize": 0 }, "text": "city" } ],
  "noDatadesc": "no datas",
  "width": 0 }

具体Java代码参考:

@Test
public void testTable() throws Exception {
  Map<String, Object> datas = new HashMap<String, Object>() {
    {
      // 有表格头 有数据
      put("table", new TableRenderData(new ArrayList<RenderData>() {
        {
          add(new TextRenderData("1E915D", "province"));
          add(new TextRenderData("1E915D", "city"));
        }
      }, new ArrayList<Object>() {
        {
          add("beijing;beijing");
          add("zhejiang;hangzhou");
        }
      }, "no datas", 0));
    }
  };
  XWPFTemplate template = XWPFTemplate.compile("src/test/resources/table.docx").render(datas);

  FileOutputStream out = new FileOutputStream("out_table.docx");
  template.write(out);
  out.flush();
  out.close();
  template.close();
}

表格的宽度怎么定义的

是一个点的二十分之一,或者是1440分之一英寸。官方解释如下:

dxa - Specifies that the value is in twentieths of a point (1/1440 of an inch).
首先1英寸=2.54厘米,A4纸大小为21cm*29.7cm。
如果这个width设置成5670,则表示这个表格的宽度是10cm。

抛开对这个单位理解的难度,我们最常见的应该是宽度自适应和宽度最大。
如果在poi-tl中设置了width=0,则表格是宽度自适应的。
以A4纸为例,页面宽度为21cm,左右页边距各位3.17cm,则表格的width=(21-3.17*2)/2.54*1440,大约为8310。

合并单元格

但是,很多业务场景并不仅限于如此简单的表格布局,产品需求总是丰富多彩的。poi-tl对XWPFDocument进行了封装,增强实现了一些基本功能。在com.deepoove.poi.NiceXWPFDocument中提供了合并的功能。

/** * 合并行单元格 * @param table * @param row * @param fromCol * @param toCol */
public void mergeCellsHorizonal(XWPFTable table, int row, int fromCol,
    int toCol)

/**
 * 合并列单元格
 * @param table
 * @param col
 * @param fromRow
 * @param toRow
 */
public void mergeCellsVertically(XWPFTable table, int col, int fromRow,
    int toRow)

自定义表格之新建表格

我们完全可以从无到有去创建一个新的表格。

  1. 无需事先创建表格,在docx中,直接输入{{table}}
  2. 默认{{table}}是文本模板,我们需要通过registerPolicy设置此模板为自定义模板。
XWPFTemplate template = XWPFTemplate.compile("src/test/resources/complex.docx");
template.registerPolicy("table", new MyTableRenderPolicy());
  1. 新建MyTableRenderPolicy.java,实现RenderPolicy接口
@Override
public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
  NiceXWPFDocument doc = template.getXWPFDocument();
  RunTemplate runTemplate = (RunTemplate) eleTemplate;
  XWPFRun run = runTemplate.getRun();
  if (null == data) return;

  //doc.insertNewTable(run, row, col);
  //doc.mergeCellsHorizonal(table, 1, 0, 1);
  //...
  runTemplate.getRun().setText("", 0);
}

至此,我们持有了NiceXWPFDocument和XWPFRun对象,可以插入表格,合并单元格等操作。

自定义表格之动态处理已有表格

对于事先已知道部分表格样式,我们只需要处理剩余部分的表格可以采用此方式。

比如下图,我们在模板中设计好表格头和表格未的样式,表格中间的数据则可以动态处理。
poi操作表格table

  1. 定义如图的模板,在表格内输入模板元素{{table}}
  2. 通过registerPolicy设置此模板为自定义模板
  3. 新建MyTableRenderPolicy.java,继承DynamicTableRenderPolicy
public class MyTableRenderPolicy extends DynamicTableRenderPolicy {

  @Override
  public void render(XWPFTable table, Object data) {
      //table.getRow(1).getCell(0)
      //XWPFTableRow row = table.insertNewTableRow(1);
      //table.removeRow(1);
  }
}

至此,我们可以通过XWPFTable对象对表格进行删除行列、增加行列、设置文字等操作。