接到的需求是在模板表格的指定位置再插入表格。比如在模板的${proTable}处插入表格。
依赖的包
<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>
插入表格
由于是在表格里的指定地方插入表格,所以要遍历表格的每个单元格,查找到要插入点的占位符。
// 处理表 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; }
// 在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); } } } } } }
// 插入并设置表格的值 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格式。这里是截取部分,比如:
<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属性,操作文本
// 设置表格边框 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"); }
// 添加单元格属性 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写入到对应的流中。
FileOutputStream fopts = new FileOutputStream("E://andy.docx"); doc.write(fopts);