word导出 poi-tl 动态表格、合并单元格
1、动态表格 {{#var}}
2、列表 {{*var}}
3、区块对 {{?sections}} {{/sections}}
4、SpringEL表达式使用
5、表格单元格合并
注意:表格外使用{{test}},表格内使用[test] 设置变量
一、动态表格
1、使用TableRenderData
eg1: 基础表格
// 一个2行2列的表格
put("table0", Tables.of(new String[][] {
new String[] { "00", "01" },
new String[] { "10", "11" }
}).border(BorderStyle.DEFAULT).create());
eg2:表格样式示例
// 表头居中且背景为蓝色
RowRenderData row0 = Rows.of("姓名", "学历").textColor("FFFFFF")
.bgColor("4472C4").center().create();
RowRenderData row1 = Rows.create("李四", "博士");
put("table1", Tables.create(row0, row1));
2、使用List
![word中表格,表头固定](https://img-blog.csdnimg.cn/c6242c1a70e24faf9db63101a1430dc1.png)
上图为word中表格,表头固定
List<Map<String, Object>> table1 = new ArrayList<>();
for(int i = 0; i < 5; i++) {
Map<String, Object> zkMap = new HashMap<>();
zkMap.put("name", "张三" + i);
zkMap.put("age", 25);
zkMap.put("job", "xxx");
zkMap.put("conten", "xxx");
zkMap.put("year", "2023");
table1.add(zkMap);
}
二、列表
1、NumberingRenderData
eg1:默认
map.put("list", Numberings.create("Plug-in grammar",
"Supports word text, pictures, table...",
"Not just templates"));
eg2:设置编号样式Numberings.of(NumberingFormat)
// DECIMAL //1. 2. 3.
// DECIMAL_PARENTHESES //1) 2) 3)
// BULLET //● ● ●
// LOWER_LETTER //a. b. c.
// LOWER_ROMAN //i ⅱ ⅲ
// UPPER_LETTER //A. B. C.
map.put("list", Numberings.of(NumberingFormat.DECIMAL)
.addItem("Plug-in grammar")
.addItem("Supports word text").create());
2、List
三、区块对 {{?sections}}{{/sections}}
标签内的内容:false或空集合时不显示标签元素
循环中的内置变量:
eg1:简单示例
{{?ex}}
{{titile}}
{{/ex}}
eg2:表格循环
word 示例:
最外层的类:
@Data
public class TReportInformDataVO {
@ApiModelProperty(value = "报告日期")
private String generateDate;
@ApiModelProperty(value = "gk数据")
private List<InformGKDataVO> GKDESC;
}
循环表格的类:
@Data
public static class InformGKDataVO {
@ApiModelProperty(value = "表格index")
private Integer index;
@ApiModelProperty(value = "企业名称")
private String entName;
private String reportYear;
private String reportMonth;
@ApiModelProperty(value = "gk数据表格")
private List<InformGKTableDataVO> gkTable;
@Data
public static class InformGKTableDataVO {
@ApiModelProperty(value = "名称")
private String name;
@ApiModelProperty(value = "数据项")
private String item;
@ApiModelProperty(value = "单位")
private String unit;
@ApiModelProperty(value = "填报值")
private String reportData;
@ApiModelProperty(value = "gk数据")
private String gkData;
@ApiModelProperty(value = "偏差")
private String offset;
}
}
结果如下:
四、SpringEL表达式使用
注意:
1、使用SpringEL表达式需要将标签配置为SpringEL模式
2、表达式在idea 或 其他文本工具 写好后再复制到word文档中
// java
builder.useSpringEL();
SpringEL表达式:
# 日期格式化
{{new java.text.SimpleDateFormat('yyyy-MM-dd HH:mm:ss').format(time)}}
# 三目运算
{{sex ? '男' : '女'}}
# 设置文本样式:可以使用el表达式,也可以在java代码里设置
[status=='0'?'通过':new com.deepoove.poi.data.TextRenderData('FF0000','不通过')]
五、表格单元格合并
合并单元格的Policy,继承DynamicTableRenderPolicy
@Accessors(chain = true)
public class MergeRowModelRenderPolicy extends DynamicTableRenderPolicy {
// 需要合并的列,从0开始
List<Integer> mergeColumns = Arrays.asList(0);
// 表格所有的列数
Integer colNum = 5;
@Override
public void render(XWPFTable table, Object data) throws Exception {
if (data == null) {
return;
}
if (CollUtil.isEmpty(mergeColumns)) {
return;
}
if (colNum == null) {
return;
}
// 需要处理的数据
List<TReportInformDataVO.InformGKDataVO.InformGKTableDataVO> dataList = (List<TReportInformDataVO.InformGKDataVO.InformGKTableDataVO>) data;
// 表格所有行
List<RowRenderData> detailData = new ArrayList<>();
if (data != null) {
table.removeRow(1);
for (int i = dataList.size() - 1; i >= 0; i--) {
//根据数据长度创建对应行数
XWPFTableRow insertNewTableRow = table.insertNewTableRow(1);
for (int j = 0; j < colNum; j++) {
//根据列的数量创建对应单元格
insertNewTableRow.createCell();
}
// 单行渲染
TReportInformDataVO.InformGKDataVO.InformGKTableDataVO item = dataList.get(i);
// rowBuilder.center().verticalCenter() 表格内容居中
// rowBuilder.rowAtleastHeight(1) 设置表格高度
RowRenderData rowRenderData = Rows.of(item.getGeneratorSystemName(), item.getItem() + "(" + item.getUnit() + ")", item.getReportData(), item.getGkData(), item.getOffset()).center().verticalCenter().rowAtleastHeight(1).create();
detailData.add(rowRenderData);
// 填充表格
TableRenderPolicy.Helper.renderRow(table.getRow(1), rowRenderData);
}
List<Map<Integer, MergeRowVo>> lstCol = new ArrayList<>();
// 循环列
mergeColumns.forEach(x -> {
Map<Integer, MergeRowVo> mapsCol = new HashMap<>();
for (int i = 0; i < detailData.size(); i++) {
// 要和下一行的内容比较,避免数组越界
if (i + 1 > detailData.size() - 1) {
break;
}
List<CellRenderData> cells = detailData.get(i).getCells();
List<CellRenderData> nextCells = detailData.get(i + 1).getCells();
// ***默认单元格合并要参考第0列
if (cells.get(0).getParagraphs().get(0).getContents().get(0).toString().equals(nextCells.get(0).getParagraphs().get(0).getContents().get(0).toString())) {
// 判断第x列 == 第x+1列 ?
if (cells.get(x).getParagraphs().get(0).getContents().get(0).toString().equals(nextCells.get(x).getParagraphs().get(0).getContents().get(0).toString())) {
if (mapsCol.containsKey(x)) {
mapsCol.put(x, new MergeRowVo().setStartRow(mapsCol.get(x).getStartRow()).setEndRow(i + 2));
} else {
mapsCol.put(x, new MergeRowVo().setStartRow(i + 1).setEndRow(i + 2));
}
}
} else {
lstCol.add(new HashMap<>(mapsCol));
mapsCol.clear();
}
}
if (mapsCol.size() > 0) {
lstCol.add(new HashMap<>(mapsCol));
mapsCol.clear();
}
});
lstCol.forEach(mapsCol -> {
mapsCol.keySet().forEach(key -> {
// 单元格合并
TableTools.mergeCellsVertically(table, key, mapsCol.get(key).getStartRow(), mapsCol.get(key).getEndRow());
});
});
}
}
}
六、官方示例
地址:
poi-tl官方示例:http://deepoove.com/poi-tl/#_%E7%A4%BA%E4%BE%8B_5