package com.product.print.service; import cn.hutool.core.collection.CollectionUtil; import com.deepoove.poi.NiceXWPFDocument; import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.policy.RenderPolicy; import com.deepoove.poi.template.ElementTemplate; import com.deepoove.poi.template.run.RunTemplate; import com.product.common.lang.StringUtils; import org.apache.poi.xwpf.usermodel.*; import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlObject; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author cheng * @desc poi-tl 自定义字表渲染 * @date 2022年5月6日17:04:31 */ public class HackLoopTableRenderPolicy implements RenderPolicy { @Override public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) { NiceXWPFDocument doc = template.getXWPFDocument(); RunTemplate runTemplate = (RunTemplate) eleTemplate; XWPFRun run = runTemplate.getRun(); String text = run.getText(0); try { // w:tbl-w:tr-w:tc-w:p-w:tr XmlCursor newCursor = ((XWPFParagraph) run.getParent()).getCTP().newCursor(); newCursor.toParent(); newCursor.toParent(); newCursor.toParent(); XmlObject object = newCursor.getObject(); XWPFTable table = doc.getAllTable((CTTbl) object); render(text, table, (List>) data, template, text.substring(2).substring(0, text.length() - 4)); run.setText("", 0); } catch (Exception e) { logger.error("dynamic table error:" + e.getMessage(), e); } } private void render(String text, XWPFTable table, List> subListData, XWPFTemplate template, String subTableName) { List rows = table.getRows(); if (rows != null && rows.size() > 0) { //表格渲染开始行(子表字段表达式所在行) int tableRowIndex = -1; for (int i = 0; i < rows.size(); i++) { XWPFTableCell cell = rows.get(i).getCell(0); if (cell != null && cell.getText().indexOf(text) != -1) { tableRowIndex = i + 1; break; } } if (tableRowIndex > -1) { XWPFTableRow xwpfTableRow = rows.get(tableRowIndex); List cells = xwpfTableRow.getTableCells(); if (cells != null && cells.size() > 0) { String[] keys = new String[cells.size()]; for (int i = 0; i < cells.size(); i++) { XWPFTableCell xwpfTableCell = cells.get(i); String expression = xwpfTableCell.getText(); if (!StringUtils.isEmpty(expression.trim())) { expression = expression.trim(); keys[i] = parseString(expression, subTableName); } } table.removeRow(tableRowIndex); if (CollectionUtil.isEmpty(subListData)) { return; } for (int i = 0; i < subListData.size(); i++) { table.insertNewTableRow(tableRowIndex); XWPFTableRow currentRow = table.getRow(tableRowIndex); int cellCount = cells.size() < keys.length ? keys.length : cells.size(); for (int j = 0; j < cellCount; j++) { currentRow.addNewTableCell(); } setValues(table.getRow(tableRowIndex).getTableCells(), keys, subListData.get(i)); tableRowIndex++; } } } } } private void setValues(List cells, String[] keys, Map subData) { if (cells != null && keys != null && cells.size() > 0 && subData != null && subData.size() > 0) { for (int i = 0; i < cells.size(); i++) { String key = keys[i]; if (StringUtils.isEmpty(key)) { continue; } Object val = subData.get(key) ; if (val == null) { val = ""; } cells.get(i).setText(val+""); } } } /** * 解析字符串 */ public static String parseString(String text, String table) { Matcher matcher = Pattern.compile("(\\$\\{)(" + makeQueryStringAllRegExp(table) + "\\.+)([\\w]+)(\\})").matcher(text); StringBuilder sb = new StringBuilder(); while (matcher.find()) { System.out.println(matcher.group()); sb.append(matcher.group(3)); } return sb.length() > 0 ? sb.toString() : null; } /** * 转义正则特殊字符 ($()*+.[]?\^{} * \\需要第一个替换,否则replace方法替换时会有逻辑bug */ public static String makeQueryStringAllRegExp(String str) { if (StringUtils.isBlank(str)) { return str; } return str.replace("\\", "\\\\").replace("*", "\\*") .replace("+", "\\+").replace("|", "\\|") .replace("{", "\\{").replace("}", "\\}") .replace("(", "\\(").replace(")", "\\)") .replace("^", "\\^").replace("$", "\\$") .replace("[", "\\[").replace("]", "\\]") .replace("?", "\\?").replace(",", "\\,") .replace(".", "\\.").replace("&", "\\&"); } }