poi-tl渲染word复杂表格(合并行,列)
poi-tl(poi template language)是Word模板引擎,基于Microsoft Word模板和数据生成新的文档。
官方文档: http://deepoove.com/poi-tl github: https://github.com/Sayi/poi-tl
该项目基于Apache-poi操作word, 通过标签渲染模板十分方便, 本文主要研究如何实现相对复杂的word表格 模板:
实现效果图
代码:
代码语言:javascript复制package cn.exrick.xboot.modules.report.controller.policyimpl;
import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.data.TextRenderData;
import com.deepoove.poi.data.style.TableStyle;
import com.deepoove.poi.policy.DynamicTableRenderPolicy;
import com.deepoove.poi.policy.MiniTableRenderPolicy;
import com.deepoove.poi.util.TableTools;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBorder;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblBorders;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STBorder;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
import java.math.BigInteger;
import java.util.*;
/**
* 生成word复杂表
*/
public class DyyxTablePolicy extends DynamicTableRenderPolicy {
private String lastName = "";
private int k = 1;
private int i = 0;
private int j = 0;
private int j2 = 0;
@Override
public void render(XWPFTable table, Object data) {
this.k = 1;
this.i = 0;
this.j = 0;
this.j2 = 0;
this.lastName = "";
setTable(table);
if (null == data) return;
List<Map<String, Object>> tableData = (List<Map<String, Object>>) data;
List<RowRenderData> dest = new LinkedList<>();
TableStyle rowStyle = new TableStyle();
rowStyle.setAlign(STJc.CENTER);
TreeMap<Integer, Integer> mergeMap = new TreeMap<>();
//list-map转list-RowRenderData-list
tableData.forEach(o -> {
//Map转普通List
List<String> list = new ArrayList<String>() {{
if (!lastName.equals(o.get("company").toString())) {
add(o.get("index").toString());
add(o.get("company").toString());
//预处理合并列
if (o.get("company").toString().matches(".*中心")) {
mergeMap.put(j, 1);
j2 = j;
}
} else {
//预处理合并列
mergeMap.put(j2, mergeMap.get(j2) 1);
add("");
add("");
}
add(o.get("dyyj").toString());
add(o.get("dykh").toString());
add(o.get("gyyj").toString());
add(o.get("gykh").toString());
}};
this.j ;
lastName = o.get("company").toString();
if (!" - ".equals(o.get("group").toString())) {
list.add(2, o.get("group").toString());
}
//普通List转RowRenderData-list
String[] values = new String[list.size()];
list.toArray(values);
System.out.println(list);
RowRenderData build = RowRenderData.build(values);
build.setRowStyle(rowStyle);
dest.add(build);
});
dest.forEach(o -> {
TextRenderData text = o.getCells().get(0).getCellText();
TextRenderData text1 = o.getCells().get(1).getCellText();
//对索引重定义
if (text1.getText().matches("(.*公司)|(.*中心)")) {
text.setText(Integer.valueOf(k).toString());
this.k ;
}
//行合并起点
if (!o.getCells().get(1).getCellText().getText().matches(".*公司")) {
this.i ;
}
});
/*
处理列合并索引
1. 匹配 中心 单位 记录出现位置 到map<位置,次数>
2. 相同单位时map的value自增
3. 遍历map 位置 = 位置加自增数
4. 合并时,从位置-自增数 到位置合并
*/
TreeMap<Integer, Integer> temp = new TreeMap<>();
mergeMap.forEach((k, v) -> {
temp.put(k v, v);
});
mergeMap.clear();
mergeMap.putAll(temp);
if (tableData == null) {
return;
}
// 循环插入行
table.removeRow(2);
for (int i = 0; i < dest.size(); i ) {
XWPFTableRow insertNewTableRow = table.insertNewTableRow(2 i);
for (int j = 0; j < 7; j ) {
insertNewTableRow.createCell()
.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
}
// 合并垂直单元格
if (mergeMap.get(i) != null) {
Integer colNum = mergeMap.get(i);
int flag = i == this.i ? 1 : 0;
TableTools.mergeCellsVertically(table, 0, 2 i - colNum, 2 i - flag);
TableTools.mergeCellsVertically(table, 1, 2 i - colNum, 2 i - flag);
}
// 合并水平单元格
if (i >= this.i) {
TableTools.mergeCellsHorizonal(table, 2 i, 1, 2);
}
MiniTableRenderPolicy.Helper.renderRow(table, 2 i, dest.get(i));
}
}
/**
* 单元格加边框
*
* @param table
*/
private void setTable(XWPFTable table) {
CTTblBorders borders = table.getCTTbl().getTblPr().addNewTblBorders();
CTBorder hBorder = borders.addNewInsideH();
hBorder.setVal(STBorder.Enum.forString("single")); // 线条类型
hBorder.setSz(new BigInteger("1")); // 线条大小
hBorder.setColor("000000"); // 设置颜色
CTBorder vBorder = borders.addNewInsideV();
vBorder.setVal(STBorder.Enum.forString("single"));
vBorder.setSz(new BigInteger("1"));
vBorder.setColor("000000");
CTBorder lBorder = borders.addNewLeft();
lBorder.setVal(STBorder.Enum.forString("single"));
lBorder.setSz(new BigInteger("1"));
lBorder.setColor("000000");
CTBorder rBorder = borders.addNewRight();
rBorder.setVal(STBorder.Enum.forString("single"));
rBorder.setSz(new BigInteger("1"));
rBorder.setColor("000000");
CTBorder tBorder = borders.addNewTop();
tBorder.setVal(STBorder.Enum.forString("single"));
tBorder.setSz(new BigInteger("1"));
tBorder.setColor("000000");
CTBorder bBorder = borders.addNewBottom();
bBorder.setVal(STBorder.Enum.forString("single"));
bBorder.setSz(new BigInteger("1"));
bBorder.setColor("000000");
}
}