diff --git a/casic-metering-service/pom.xml b/casic-metering-service/pom.xml index ca7a53a..4f81644 100644 --- a/casic-metering-service/pom.xml +++ b/casic-metering-service/pom.xml @@ -48,6 +48,12 @@ com.new.reader reader-api + + + com.deepoove + poi-tl + 1.10.0 + \ No newline at end of file diff --git a/casic-metering-service/pom.xml b/casic-metering-service/pom.xml index ca7a53a..4f81644 100644 --- a/casic-metering-service/pom.xml +++ b/casic-metering-service/pom.xml @@ -48,6 +48,12 @@ com.new.reader reader-api + + + com.deepoove + poi-tl + 1.10.0 + \ No newline at end of file diff --git a/casic-metering-service/src/main/java/com/casic/missiles/service/listeners/register/FilePrintRegisterUtils.java b/casic-metering-service/src/main/java/com/casic/missiles/service/listeners/register/FilePrintRegisterUtils.java index 372d23d..ce6f812 100644 --- a/casic-metering-service/src/main/java/com/casic/missiles/service/listeners/register/FilePrintRegisterUtils.java +++ b/casic-metering-service/src/main/java/com/casic/missiles/service/listeners/register/FilePrintRegisterUtils.java @@ -428,8 +428,8 @@ } String tmpPath = ""; try { - ParseWord07 parseWord07=new ParseWord07(); - XWPFDocument doc = parseWord07.parseWord(templatePath, params); + ParseWord07 parseWord07 = new ParseWord07(); + XWPFDocument doc = parseWord07.parseWord(templatePath, params, null); tmpPath = temDir + fileName; FileOutputStream fos = new FileOutputStream(tmpPath); doc.write(fos); @@ -442,7 +442,6 @@ } - public static void main(String[] args) throws RuntimeException { String pathUrl = "D:\\casic"; String localPathUrl = "D:\\casic\\"; diff --git a/casic-metering-service/pom.xml b/casic-metering-service/pom.xml index ca7a53a..4f81644 100644 --- a/casic-metering-service/pom.xml +++ b/casic-metering-service/pom.xml @@ -48,6 +48,12 @@ com.new.reader reader-api + + + com.deepoove + poi-tl + 1.10.0 + \ No newline at end of file diff --git a/casic-metering-service/src/main/java/com/casic/missiles/service/listeners/register/FilePrintRegisterUtils.java b/casic-metering-service/src/main/java/com/casic/missiles/service/listeners/register/FilePrintRegisterUtils.java index 372d23d..ce6f812 100644 --- a/casic-metering-service/src/main/java/com/casic/missiles/service/listeners/register/FilePrintRegisterUtils.java +++ b/casic-metering-service/src/main/java/com/casic/missiles/service/listeners/register/FilePrintRegisterUtils.java @@ -428,8 +428,8 @@ } String tmpPath = ""; try { - ParseWord07 parseWord07=new ParseWord07(); - XWPFDocument doc = parseWord07.parseWord(templatePath, params); + ParseWord07 parseWord07 = new ParseWord07(); + XWPFDocument doc = parseWord07.parseWord(templatePath, params, null); tmpPath = temDir + fileName; FileOutputStream fos = new FileOutputStream(tmpPath); doc.write(fos); @@ -442,7 +442,6 @@ } - public static void main(String[] args) throws RuntimeException { String pathUrl = "D:\\casic"; String localPathUrl = "D:\\casic\\"; diff --git a/casic-metering-service/src/main/java/com/casic/missiles/service/listeners/util/ParseWord07.java b/casic-metering-service/src/main/java/com/casic/missiles/service/listeners/util/ParseWord07.java index 2547722..656fa51 100644 --- a/casic-metering-service/src/main/java/com/casic/missiles/service/listeners/util/ParseWord07.java +++ b/casic-metering-service/src/main/java/com/casic/missiles/service/listeners/util/ParseWord07.java @@ -7,24 +7,93 @@ import cn.afterturn.easypoi.word.entity.params.ExcelListEntity; import cn.afterturn.easypoi.word.parse.excel.ExcelEntityParse; import cn.afterturn.easypoi.word.parse.excel.ExcelMapParse; +import cn.hutool.core.collection.CollectionUtil; +import liquibase.pro.packaged.A; import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.xwpf.usermodel.*; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.math.BigInteger; import java.util.*; +import java.util.stream.Collector; import java.util.stream.Collectors; /** * poi 类不满足列循环格式插入,修改源码后满足 - * */ public class ParseWord07 { - private static final Logger LOGGER = LoggerFactory.getLogger(cn.afterturn.easypoi.word.parse.ParseWord07.class); + + private static final Logger LOGGER = LoggerFactory.getLogger(ParseWord07.class); public ParseWord07() { } + /** + * word 解析入口类 + * + * @param url + * @param map + * @return + * @throws Exception + */ + public XWPFDocument parseWord(String url, Map map, List mergeColNames) throws Exception { + MyXWPFDocument doc = WordCache.getXWPFDocument(url); + this.parseWordSetValue(doc, map, mergeColNames); + return doc; + } + + /** + * 处理段落的{{ }}内容 + * 处理 + * + * @param doc + * @param map + * @throws Exception + */ + private void parseWordSetValue(MyXWPFDocument doc, Map map, List mergeColNames) throws Exception { + this.parseAllParagraph(doc.getParagraphs(), map); + this.parseHeaderAndFoot(doc, map); + Iterator itTable = doc.getTablesIterator(); + //处理表格替换 + while (itTable.hasNext()) { + XWPFTable table = (XWPFTable) itTable.next(); + if (table.getText().indexOf("{{") != -1) { + this.parseThisTable(table, map, mergeColNames); + } + } + } + + /** + * 处理word中包含所有的段落 + * + * @param paragraphs + * @param map + * @throws Exception + */ + private void parseAllParagraph(List paragraphs, Map map) throws Exception { + for (int i = 0; i < paragraphs.size(); ++i) { + XWPFParagraph paragraph = (XWPFParagraph) paragraphs.get(i); + if (paragraph.getText().indexOf("{{") != -1) { + this.parseThisParagraph(paragraph, map); + } + } + } + + /** + * 核心替换方法 + *

+ * 段落处理段落,执行替换的情况 + * + * @param paragraph + * @param currentRun + * @param currentText 当前内容 + * @param runIndex 当前内容对应的下标 + * @param map 要替换成的参数集合 + * @throws Exception + */ private void changeValues(XWPFParagraph paragraph, XWPFRun currentRun, String currentText, List runIndex, Map map) throws Exception { if (currentText.contains("fe:") && currentText.startsWith("{{")) { currentText = currentText.replace("fe:", "").replace("{{", "").replace("}}", ""); @@ -37,7 +106,6 @@ } else { PoiPublicUtil.setWordText(currentRun, objx.toString()); } - }); } else { Object obj = PoiPublicUtil.getRealValue(currentText, map); @@ -49,15 +117,15 @@ PoiPublicUtil.setWordText(currentRun, currentText); } } - for (int k = 0; k < runIndex.size(); ++k) { ((XWPFRun) paragraph.getRuns().get((Integer) runIndex.get(k))).setText("", 0); } - runIndex.clear(); } - private void checkThisTableCellIterator(List cells, Map map) throws Exception { + //先执行预匹配,获取最大的长度,在进行之下的扩容 + private Boolean checkThisTableCellIterator(List cells, XWPFTable table, + Map map, int row, Integer maxExpansionLength, Integer differExpansionLength) throws Exception { int cellIndex = 0; while (cellIndex < cells.size()) { String text = cells.get(cellIndex).getText().trim(); @@ -66,24 +134,191 @@ } cellIndex++; } - if (cellIndex >= cells.size()) { - return; + int currentIndex = cells.size() - 1; + //涉及扩容 + while (cells.size() - currentIndex < differExpansionLength) { + cells.get(0).getTableRow().createCell(); + } + //合并,且去除合并包含都是一列的情况 + if (currentIndex + 1 < (maxExpansionLength - differExpansionLength)) { + //列合并 + mergeCellsHorizontal(cells, currentIndex, currentIndex + differExpansionLength - 1); + } + if (cellIndex >= currentIndex) { + return false; } String text = cells.get(cellIndex).getText().trim(); + return parseNextColAndAddCol(cells, text, cellIndex, map, table); + } + + + /** + * 解析列,并自动增加列 + */ + private Boolean parseNextColAndAddCol(List cells, String text, int cellIndex, Map map, XWPFTable table) throws Exception { if (text != null && text.contains("fe:") && text.startsWith("{{")) { text = text.replace("#fe:", "").replace("{{", "").replace("}}", ""); String[] keys = text.replaceAll("\\s{1,}", " ").trim().split(" "); - String[] parmkeys = keys[0].split("\\."); + String[] paramKeys = keys[0].split("\\."); Object result = PoiPublicUtil.getParamsValue(keys[0], map); if (result instanceof List) { List> resultMap = (List>) result; - List resultList = resultMap.stream().map(m -> m.get(parmkeys[parmkeys.length - 1])).collect(Collectors.toList()); + List resultList = resultMap.stream().map(m -> m.get(paramKeys[paramKeys.length - 1])).collect(Collectors.toList()); int resultIndex = 0; + //清理参数 clearParagraphText((cells.get(cellIndex)).getParagraphs()); - while (resultIndex < resultList.size() && cellIndex < cells.size()) { - cells.get(cellIndex++).setText(String.valueOf(resultList.get(resultIndex))); - resultIndex++; + //涉及扩容 + Integer differCol = cells.size() - cellIndex; + BigInteger weight = table.getCTTbl().getTblGrid().getGridColList().get(0).getW(); + for (CTTblGridCol ctTblGridCol : table.getCTTbl().getTblGrid().getGridColList()) { + ctTblGridCol.setW(weight); } + //改变不了原来的格式,例如光标位置 + while (resultIndex < resultList.size() && cellIndex < cells.size()) { + if (resultIndex >= differCol) { + CTTbl currentTbl = table.getCTTbl(); + CTTblGrid tblGrid = currentTbl.getTblGrid() != null ? currentTbl.getTblGrid() + : currentTbl.addNewTblGrid(); + tblGrid.addNewGridCol().setW(weight); + } + cells.get(cellIndex).setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); + cells.get(cellIndex++).setText(String.valueOf(resultList.get(resultIndex++))); + } + return true; + } + } + return false; + } + + /** + * 合并行的算法 + */ + private void mergeCell(XWPFTable table, List mergeColNames) { + //表头检测 + if (CollectionUtil.isNotEmpty(mergeColNames)) { + //遍寻列,同时增加下标超值判断 + int positionIndex = tryGetInitialMergeRow(table); + List mergeIndexList = checkThisTableCellMergeIndex(positionIndex, table, mergeColNames); + + Map mergeIndexMap = mergeIndexList.stream().collect(Collectors.toMap(e -> e, e -> e)); + //直到查询的上下列不一样的时候,停止遍历列的循环,停止遍历 + while (positionIndex < table.getNumberOfRows()) { + XWPFTableRow row = table.getRow(positionIndex); + if (row == null) { + return; + } + int startIndex = positionIndex, maxEndIndex = positionIndex; + for (int i = 0; i < row.getTableCells().size(); i++) { + if (!mergeIndexMap.containsKey(i)) { + continue; + } + int endIndex = positionIndex; + int rowIndex = positionIndex + 1; + while ((maxEndIndex > positionIndex && rowIndex <= maxEndIndex) || + (maxEndIndex == positionIndex && rowIndex < table.getNumberOfRows())) { + if (table.getRow(rowIndex).getTableCells().get(i).getText().equals(row.getCell(i).getText())) { + endIndex = rowIndex; + rowIndex++; + } else { + break; + } + } + maxEndIndex = i == 0 ? endIndex : maxEndIndex; + if (endIndex > startIndex) { + doMergeCell(table, startIndex, endIndex, i); + } + } + positionIndex = maxEndIndex + 1; + } + } + } + + private Integer tryGetInitialMergeRow(XWPFTable table) { + int positionIndex = 1, initialMergeRow = 0; + while (positionIndex < table.getNumberOfRows()) { + if (StringUtils.isEmpty(table.getRow(positionIndex).getTableCells().get(0).getText())) { + initialMergeRow = ++positionIndex; + } else { + return initialMergeRow; + } + } + return initialMergeRow; + } + + private List checkThisTableCellMergeIndex(int positionIndex, XWPFTable table, List mergeColNames) { + Map mergeColNameMap = mergeColNames.stream().collect( + Collectors.toMap(e -> e, e -> e) + ); + int colIndex = 0; + List mergeIndexList = new ArrayList<>(); + for (int i = 0; i < --positionIndex; i++) { + XWPFTableRow row = table.getRow(i); + //标题合并行 + while (colIndex < row.getTableCells().size()) { + String titleText = row.getTableCells().get(colIndex).getText(); + if (StringUtils.isNotEmpty(titleText)) { + if (mergeColNameMap.containsKey(titleText)) { + //合并两行的存在 + if (i < positionIndex) { + Integer mergerIndex = 0; + List cells = table.getRow(positionIndex).getTableCells(); + for (int j = 0; j < cells.size(); ) { + //获取当前所在行为空, + if (StringUtils.isNotEmpty(cells.get(j).getText())) { + if (++mergerIndex > colIndex) { + mergeIndexList.add(j - 1); + break; + } + while (StringUtils.isNotEmpty(cells.get(++j).getText())) { + } + } else { + j++; + if (++mergerIndex > colIndex) { + mergeIndexList.add(j - 1); + break; + } + } + } + } else { + mergeIndexList.add(colIndex); + } + } + } + colIndex++; + } + } + return mergeIndexList; + } + + /** + * 执行合并行列算法的核心方法 + */ + private static void doMergeCell(XWPFTable table, int beginRowIndex, int endRowIndex, int colIndex) { + if (beginRowIndex == endRowIndex || beginRowIndex > endRowIndex) { + return; + } + //合并行单元格的第一个单元格 + CTVMerge startMerge = CTVMerge.Factory.newInstance(); + startMerge.setVal(STMerge.RESTART); + //合并行单元格的第一个单元格之后的单元格 + CTVMerge endMerge = CTVMerge.Factory.newInstance(); + endMerge.setVal(STMerge.CONTINUE); + table.getRow(beginRowIndex).getCell(colIndex).getCTTc().getTcPr().setVMerge(startMerge); + for (int i = beginRowIndex + 1; i <= endRowIndex; i++) { + table.getRow(i).getCell(colIndex).getCTTc().getTcPr().setVMerge(endMerge); + } + } + + + public void mergeCellsHorizontal(List cells, int fromCell, int toCell) { + for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) { + XWPFTableCell cell = cells.get(cellIndex); + if (cellIndex == fromCell) { + // The first merged cell is set with RESTART merge value + cell.getCTTc().getTcPr().addNewHMerge().setVal(STMerge.RESTART); + } else { + // Cells which join (merge) the first one, are set with CONTINUE + cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE); } } } @@ -98,28 +333,29 @@ }); } - private Object checkThisTableIsNeedIterator(XWPFTableCell cell, Map map) throws Exception { + /** + * 行循环检测 + */ + private Object checkThisTableIsNeedIterator(XWPFTableCell cell, Map map, List mergeColNames) throws + Exception { + //增加嵌套表格的填充数据 + List tableNestList = cell.getTables(); + for (XWPFTable nestTable : tableNestList) { + if (nestTable.getText().indexOf("{{") != -1) { + this.parseThisTable(nestTable, map, mergeColNames); + } + } String text = cell.getText().trim(); - if (text != null && text.contains("fe:") && text.startsWith("{{")) { + if (StringUtils.isNotEmpty(text) && text.contains("fe:") && text.startsWith("{{")) { text = text.replace("!fe:", "").replace("$fe:", "").replace("fe:", "").replace("{{", ""); String[] keys = text.replaceAll("\\s{1,}", " ").trim().split(" "); Object result = PoiPublicUtil.getParamsValue(keys[0], map); - return Objects.nonNull(result) ? result : new ArrayList(0); + return Objects.isNull(result) ? null : result instanceof String ? null : result; } else { return null; } } - private void parseAllParagraph(List paragraphs, Map map) throws Exception { - for (int i = 0; i < paragraphs.size(); ++i) { - XWPFParagraph paragraph = (XWPFParagraph) paragraphs.get(i); - if (paragraph.getText().indexOf("{{") != -1) { - this.parseThisParagraph(paragraph, map); - } - } - - } - private void parseThisParagraph(XWPFParagraph paragraph, Map map) throws Exception { XWPFRun currentRun = null; String currentText = ""; @@ -129,6 +365,7 @@ XWPFRun run = (XWPFRun) paragraph.getRuns().get(i); String text = run.getText(0); if (!StringUtils.isEmpty(text)) { + //处理循环机制的{{}} if (isfinde) { currentText = currentText + text; if (currentText.indexOf("{{") == -1) { @@ -137,12 +374,12 @@ } else { runIndex.add(i); } - if (currentText.indexOf("}}") != -1) { this.changeValues(paragraph, currentRun, currentText, runIndex, map); currentText = ""; isfinde = false; } + //处理单个{{}} } else if (text.indexOf("{{") >= 0) { currentText = text; isfinde = true; @@ -150,7 +387,7 @@ } else { currentText = ""; } - + // 真实替换处理单个{{}} if (currentText.indexOf("}}") != -1) { this.changeValues(paragraph, currentRun, currentText, runIndex, map); isfinde = false; @@ -162,7 +399,6 @@ private void parseThisRow(List cells, Map map) throws Exception { Iterator var3 = cells.iterator(); - while (var3.hasNext()) { XWPFTableCell cell = (XWPFTableCell) var3.next(); this.parseAllParagraph(cell.getParagraphs(), map); @@ -170,46 +406,45 @@ } - private void parseThisTable(XWPFTable table, Map map) throws Exception { - + private void parseThisTable(XWPFTable table, Map map, List mergeColNames) throws Exception { + //默认为当前单元格的长度 + Integer maxExpansionLength = tryMatchMaxLength(table, map); + Integer differExpansionLength = maxExpansionLength - table.getRow(0).getTableCells().size(); + //执行匹配,进行行列扩展 for (int i = 0; i < table.getNumberOfRows(); ++i) { XWPFTableRow row = table.getRow(i); List cells = row.getTableCells(); - //增加对该行列的检测 - checkThisTableCellIterator(cells, map); + //增加对该行列循环填充参数的添加 + checkThisTableCellIterator(cells, table, map, i, maxExpansionLength, differExpansionLength); //检测该行的首个字母是否是 - Object listobj = this.checkThisTableIsNeedIterator((XWPFTableCell) cells.get(0), map); - if (listobj == null) { + Object listObj = this.checkThisTableIsNeedIterator(cells.get(0), map, mergeColNames); + if (listObj == null) { this.parseThisRow(cells, map); - } else if (listobj instanceof ExcelListEntity) { - (new ExcelEntityParse()).parseNextRowAndAddRow(table, i, (ExcelListEntity) listobj); - i = i + ((ExcelListEntity) listobj).getList().size() - 1; + } else if (listObj instanceof ExcelListEntity) { + (new ExcelEntityParse()).parseNextRowAndAddRow(table, i, (ExcelListEntity) listObj); + i = i + ((ExcelListEntity) listObj).getList().size() - 1; } else { - ExcelMapParse.parseNextRowAndAddRow(table, i, (List) listobj); - i = i + ((List) listobj).size() - 1; + ExcelMapParse.parseNextRowAndAddRow(table, i, (List) listObj); + i = i + ((List) listObj).size() - 1; } } - + //单个元合并 + mergeCell(table, mergeColNames); } - public XWPFDocument parseWord(String url, Map map) throws Exception { - MyXWPFDocument doc = WordCache.getXWPFDocument(url); - this.parseWordSetValue(doc, map); - return doc; - } - public XWPFDocument parseWord(String url, List> list) throws Exception { + public XWPFDocument parseWord(String url, List> list, List mergeColNames) throws Exception { if (list != null && list.size() != 0) { if (list.size() == 1) { - return this.parseWord(url, (Map) list.get(0)); + return this.parseWord(url, (Map) list.get(0), mergeColNames); } else { MyXWPFDocument doc = WordCache.getXWPFDocument(url); - this.parseWordSetValue(doc, (Map) list.get(0)); + this.parseWordSetValue(doc, (Map) list.get(0), mergeColNames); doc.createParagraph().setPageBreak(true); for (int i = 1; i < list.size(); ++i) { MyXWPFDocument tempDoc = WordCache.getXWPFDocument(url); - this.parseWordSetValue(tempDoc, (Map) list.get(i)); + this.parseWordSetValue(tempDoc, (Map) list.get(i), mergeColNames); tempDoc.createParagraph().setPageBreak(true); doc.getDocument().addNewBody().set(tempDoc.getDocument().getBody()); } @@ -221,23 +456,17 @@ } } - public void parseWord(XWPFDocument document, Map map) throws Exception { - this.parseWordSetValue((MyXWPFDocument) document, map); + public void parseWord(XWPFDocument document, Map map, List mergeColNames) throws Exception { + this.parseWordSetValue((MyXWPFDocument) document, map, mergeColNames); } - private void parseWordSetValue(MyXWPFDocument doc, Map map) throws Exception { - this.parseAllParagraph(doc.getParagraphs(), map); - this.parseHeaderAndFoot(doc, map); - Iterator itTable = doc.getTablesIterator(); - while (itTable.hasNext()) { - XWPFTable table = (XWPFTable) itTable.next(); - if (table.getText().indexOf("{{") != -1) { - this.parseThisTable(table, map); - } - } - - } - + /** + * 处理头和尾部脚本的内容替换 + * + * @param doc + * @param map + * @throws Exception + */ private void parseHeaderAndFoot(MyXWPFDocument doc, Map map) throws Exception { List headerList = doc.getHeaderList(); Iterator var4 = headerList.iterator(); @@ -260,6 +489,46 @@ this.parseThisParagraph((XWPFParagraph) xwpfFooter.getListParagraph().get(i), map); } } + } + private Integer tryMatchMaxLength(XWPFTable table, Map map) throws Exception { + Integer maxExpansionLength = -1; + table.getRow(0).getTableCells().size(); + //预匹配,获取扩展的最大长度、 + for (int i = 0; i < table.getNumberOfRows(); ++i) { + XWPFTableRow row = table.getRow(i); + List cells = row.getTableCells(); + maxExpansionLength = doGetTableMaxColLength(cells, map, maxExpansionLength); + } + return maxExpansionLength; + } + + //先执行预匹配,获取最大的长度,在进行之下的扩容 + private Integer doGetTableMaxColLength(List cells, Map map, Integer maxExpansionLength) throws Exception { + int cellIndex = 0; + while (cellIndex < cells.size()) { + String text = cells.get(cellIndex).getText().trim(); + if (text != null && text.contains("#fe:") && text.startsWith("{{")) { + break; + } + cellIndex++; + } + //匹配失败 + if (cellIndex >= cells.size()) { + return maxExpansionLength; + } + String text = cells.get(cellIndex).getText().trim(); + if (text != null && text.contains("fe:") && text.startsWith("{{")) { + text = text.replace("#fe:", "").replace("{{", "").replace("}}", ""); + String[] keys = text.replaceAll("\\s{1,}", " ").trim().split(" "); + String[] paramKeys = keys[0].split("\\."); + Object result = PoiPublicUtil.getParamsValue(keys[0], map); + if (result instanceof List) { + List> resultMap = (List>) result; + List resultList = resultMap.stream().map(m -> m.get(paramKeys[paramKeys.length - 1])).collect(Collectors.toList()); + return maxExpansionLength > resultList.size() ? maxExpansionLength : cellIndex + 1 + resultList.size(); + } + } + return maxExpansionLength; } }