转载,原文地址:
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-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)
自定义表格之新建表格
我们完全可以从无到有去创建一个新的表格。
- 无需事先创建表格,在docx中,直接输入{{table}}
- 默认{{table}}是文本模板,我们需要通过registerPolicy设置此模板为自定义模板。
XWPFTemplate template = XWPFTemplate.compile("src/test/resources/complex.docx");
template.registerPolicy("table", new MyTableRenderPolicy());
- 新建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对象,可以插入表格,合并单元格等操作。
自定义表格之动态处理已有表格
对于事先已知道部分表格样式,我们只需要处理剩余部分的表格可以采用此方式。
比如下图,我们在模板中设计好表格头和表格未的样式,表格中间的数据则可以动态处理。
- 定义如图的模板,在表格内输入模板元素{{table}}
- 通过registerPolicy设置此模板为自定义模板
- 新建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对象对表格进行删除行列、增加行列、设置文字等操作。