POI指定位置插入表格

接到的需求是在模板表格的指定位置再插入表格。比如在模板的${proTable}处插入表格。

依赖的包

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>

<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>

插入表格

由于是在表格里的指定地方插入表格,所以要遍历表格的每个单元格,查找到要插入点的占位符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 处理表
public CustomXWPFDocument generateCoopApplyWord(Map<String, Object> param, String template) {
CustomXWPFDocument doc = null;
try {
OPCPackage pack = POIXMLDocument.openPackage(template);
doc = new CustomXWPFDocument(pack);
if (param != null && param.size() > 0) {
//处理表格
Iterator<XWPFTable> it = doc.getTablesIterator();
while (it.hasNext()) {
XWPFTable table = it.next();
List<XWPFTableRow> rows = table.getRows();
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
List<XWPFParagraph> paragraphListTable = cell.getParagraphs();
insertTable("${proTable}",param, cell); // 在"${proTable}"处插入表格
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return doc;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 在key处插入表格
private void insertTable(String key, Map<String, Object> param, XWPFTableCell cell) {
List<XWPFParagraph> paragraphList = cell.getParagraphs();
if (paragraphList != null && paragraphList.size() > 0) {
for (XWPFParagraph paragraph : paragraphList) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
String text = run.getText(0);
if (text != null) {
if (text.indexOf(key) >= 0) {
insertWhereKindTable(paragraph, param, cell);
}
}
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 插入并设置表格的值
private void insertWhereKindTable(XWPFParagraph paragraph, Map<String, Object> param, XWPFTableCell cell) {
// 得到这个指定位置的游标
XmlCursor cursor = paragraph.getCTP().newCursor();
// 在cursor插入表格
XWPFTable tableOne = cell.insertNewTbl(cursor);// ---这个是关键

// 如果自动生成了一行,可以删掉
boolean a = tableOne.removeRow(0);

// 添加属性
CTTblGrid grid = tableOne.getCTTbl().addNewTblGrid();
grid.addNewGridCol().setW(BigInteger.valueOf(2000));
grid.addNewGridCol().setW(BigInteger.valueOf(2000));
grid.addNewGridCol().setW(BigInteger.valueOf(2000));

// 设置边框样式
tableBorderStyle(tableOne);

// 这里是根据前端传过来的数据来填充表格
List<Map<String, Object>> tableValueList = (List<Map<String, Object>>) param.get("fore_com_list");

XWPFTableRow tableOneRowOne = tableOne.createRow();
tableOneRowOne.setHeight(380);
tableOneRowOne.addNewTableCell().setText("专业");
tableOneRowOne.addNewTableCell().setText("工作量");
tableOneRowOne.addNewTableCell().setText("协作比例");
tableOneRowOne.addNewTableCell().setText("协作费用");

for (int i = 0; i < tableValueList.size(); i++) {
Map<String, Object> map = tableValueList.get(i);
XWPFTableRow tableRow = tableOne.createRow();
tableRow.setHeight(380);
tableRow.getCell(0).setText((String) map.get("CoopProfessionName"));
tableRow.getCell(1).setText(String.valueOf(map.get("CoopWorkProportion")));
tableRow.getCell(2).setText(String.valueOf(map.get("CoopProportion")));
tableRow.getCell(3).setText(String.valueOf(map.get("CoopPrice")));
}

// 设置单元格样式
tableCellStyle(tableOne, 1500);
}

由于创建的新表格没有属性,比如设置边框样式,行高列宽等。POI给出了方法去设置这些属性。POI处理文档都是解析成xml格式。这里是截取部分,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<w:tbl>
<w:tblPr>
<w:tblStyle w:val="12"/>
<w:tblW w:w="9418" w:type="dxa"/>
<w:jc w:val="center"/>
<w:tblInd w:w="0" w:type="dxa"/>
<w:tblLayout w:type="fixed"/>
<w:tblCellMar>
<w:top w:w="0" w:type="dxa"/>
<w:left w:w="108" w:type="dxa"/>
<w:bottom w:w="0" w:type="dxa"/>
<w:right w:w="108" w:type="dxa"/>
</w:tblCellMar>
</w:tblPr>
<w:tblGrid>
<w:gridCol w:w="2058"/>
<w:gridCol w:w="2236"/>
<w:gridCol w:w="1455"/>
<w:gridCol w:w="3669"/>
</w:tblGrid>
<w:tr>
<w:tblPrEx>
<w:tblLayout w:type="fixed"/>
<w:tblCellMar>
<w:top w:w="0" w:type="dxa"/>
<w:left w:w="108" w:type="dxa"/>
<w:bottom w:w="0" w:type="dxa"/>
<w:right w:w="108" w:type="dxa"/>
</w:tblCellMar>
</w:tblPrEx>
<w:trPr>
<w:trHeight w:val="494" w:hRule="atLeast"/>
<w:jc w:val="center"/>
</w:trPr>
<w:tc>
<w:tcPr>
<w:tcW w:w="2058" w:type="dxa"/>
<w:tcBorders>
<w:top w:val="single" w:color="auto" w:sz="8" w:space="0"/>
<w:left w:val="single" w:color="auto" w:sz="8" w:space="0"/>
<w:bottom w:val="single" w:color="auto" w:sz="4" w:space="0"/>
<w:right w:val="single" w:color="auto" w:sz="4" w:space="0"/>
</w:tcBorders>
<w:vAlign w:val="center"/>
</w:tcPr>
<w:p>
<w:pPr>
<w:widowControl/>
<w:jc w:val="center"/>
<w:rPr>
<w:rFonts w:ascii="宋体" w:hAnsi="宋体" w:cs="宋体"/>
<w:szCs w:val="21"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia" w:ascii="宋体" w:hAnsi="宋体" w:cs="宋体"/>
<w:szCs w:val="21"/>
</w:rPr>
<w:t>项目名称</w:t>
</w:r>
</w:p>
</w:tc>

所以,如果要为新的表格设置属性,就要去操作这些节点,得到这个节点后就可以对其添加设置自己所需属性。其中:

  • CTTbl就对应上面的<w:tbl></w:tbl>,得到表格属性

  • CTRow就对应上面的<w:tr></w:tr>,得到行属性

  • CTTc就对应上面的<w:tc></w:tc>,得到列属性

  • CTP就对应上面的<w:p></w:p>,得到段落属性

  • CTR就对应上面的<w:r></w:r>,得到run属性,操作文本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 设置表格边框
private void tableBorderStyle(XWPFTable table){
//表格属性
CTTblPr tablePr = table.getCTTbl().addNewTblPr();
//表格宽度
//CTTblWidth width = tablePr.addNewTblW();
CTJc ctJc = tablePr.addNewJc();
ctJc.setVal(STJc.Enum.forString("center"));
//width.setW(BigInteger.valueOf(7000));
//width.setType(STTblWidth.DXA);

//表格颜色
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");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 添加单元格属性
private void tableCellStyle(XWPFTable table, int cellWidth) {
List<XWPFTableRow> tableRows = table.getRows();
for (int i = 0; i < tableRows.size(); i++) {
XWPFTableRow xwpfTableRow = tableRows.get(i);
List<XWPFTableCell> cellList = xwpfTableRow.getTableCells();
for (XWPFTableCell tableCell : cellList) {
CTTc ctTc = tableCell.getCTTc();
CTTcPr ctTcPr = ctTc.addNewTcPr();
ctTcPr.addNewTcW().setW(BigInteger.valueOf(cellWidth));
ctTcPr.addNewVAlign().setVal(STVerticalJc.CENTER);
ctTcPr.addNewGridSpan().setVal(BigInteger.valueOf(1));

// 添加单元格里的run属性
CTP ctp = ctTc.getPList().get(0);
CTPPr ctpPr = ctp.addNewPPr();
ctpPr.addNewWidowControl();
ctpPr.addNewJc().setVal(STJc.CENTER);
CTParaRPr ctParaRPr = ctpPr.addNewRPr();
CTFonts ctFontsp = ctParaRPr.addNewRFonts();
ctFontsp.setAscii("宋体");
ctFontsp.setHAnsi("宋体");
ctFontsp.setCs("宋体");
ctParaRPr.addNewSzCs().setVal(BigInteger.valueOf(21));


CTR ctr = ctp.getRList().get(0);
//CTR ctr = ctp.addNewR();
CTRPr ctrPr = ctr.addNewRPr();
CTFonts ctFonts = ctrPr.addNewRFonts();
ctFonts.setHint(STHint.Enum.forString("eastAsia"));
ctFonts.setEastAsia("宋体");
ctFonts.setAscii("宋体");
ctFonts.setHAnsi("宋体");
ctFonts.setCs("宋体");
ctrPr.addNewSzCs().setVal(BigInteger.valueOf(21));
}
}
}

把返回的XWPFDocument写入到对应的流中。

1
2
FileOutputStream fopts = new FileOutputStream("E://andy.docx");
doc.write(fopts);

参考资料

http://alexgl.iteye.com/blog/2326665

http://elim.iteye.com/blog/2049110

https://blog.csdn.net/qq_32918555/article/details/77606215

https://blog.csdn.net/ztt_1119/article/details/69390807

https://www.cnblogs.com/duanrantao/p/8682897.html

http://53873039oycg.iteye.com/category/302596