| | |
| | | package com.lf.server.helper; |
| | | |
| | | import org.apache.commons.logging.Log; |
| | | import org.apache.commons.logging.LogFactory; |
| | | import org.apache.poi.xwpf.usermodel.*; |
| | | import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; |
| | | |
| | | import java.io.IOException; |
| | | import java.io.InputStream; |
| | | import java.io.OutputStream; |
| | | import java.io.*; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | |
| | | /** |
| | | * Word帮助类 |
| | | * |
| | | * @author WWW |
| | | * @date 2024-03-21 |
| | | */ |
| | | @SuppressWarnings("ALL") |
| | | public class WordHelper { |
| | | private final static Log log = LogFactory.getLog(WordHelper.class); |
| | | |
| | | /** |
| | | * 通过word模板生成word的主方法 |
| | | * https://blog.csdn.net/qq_46112324/article/details/128156675 |
| | | */ |
| | | public static void generateWord(InputStream inputStream, OutputStream outputStream, Map<String, String> insertTextMap, List<String[]> addList) throws IOException { |
| | | // 获取docx解析对象 |
| | | XWPFDocument xwpfDocument = new XWPFDocument(inputStream); |
| | | public static void generateWord(String inputFile, String outPutFile, Map<String, String> textMap, List<String[]> tableList) { |
| | | FileInputStream inputStream = null; |
| | | FileOutputStream outputStream = null; |
| | | |
| | | // 处理所有文段数据,除了表格 |
| | | handleParagraphs(xwpfDocument, insertTextMap); |
| | | try { |
| | | inputStream = new FileInputStream(inputFile); |
| | | outputStream = new FileOutputStream(outPutFile); |
| | | |
| | | // 处理表格数据 |
| | | handleTable(xwpfDocument, insertTextMap, addList); |
| | | // 获取docx解析对象 |
| | | XWPFDocument document = new XWPFDocument(inputStream); |
| | | |
| | | // 写入数据 |
| | | xwpfDocument.write(outputStream); |
| | | // 处理所有文段数据,除了表格 |
| | | if (null != textMap && textMap.size() > 0) { |
| | | handleParagraphs(document, textMap); |
| | | //changeText(document, textMap); |
| | | } |
| | | |
| | | outputStream.close(); |
| | | // 解析替换表格对象 |
| | | if (null != tableList && tableList.size() > 0) { |
| | | handleTable(document, textMap, tableList); |
| | | //changeTable(document, textMap, tableList); |
| | | } |
| | | |
| | | // 写入数据 |
| | | document.write(outputStream); |
| | | document.close(); |
| | | } catch (Exception ex) { |
| | | log.error(ex.getMessage(), ex); |
| | | } finally { |
| | | try { |
| | | if (outputStream != null) { |
| | | outputStream.close(); |
| | | } |
| | | if (inputStream != null) { |
| | | inputStream.close(); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error(e.getMessage(), e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 替换表格对象方法 |
| | | * |
| | | * @param document docx解析对象 |
| | | * @param textMap 需要替换的信息集合 |
| | | * @param tableList 需要插入的表格信息集合 |
| | | */ |
| | | public static void changeTable(XWPFDocument document, Map<String, String> textMap, List<String[]> tableList) { |
| | | // 获取表格对象集合 |
| | | List<XWPFTable> tables = document.getTables(); |
| | | for (int i = 0; i < tables.size(); i++) { |
| | | XWPFTable table = tables.get(i); |
| | | if (table.getRows().size() > 1) { |
| | | // 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入 |
| | | if (!checkText(table.getText())) { |
| | | insertTable(table, tableList); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 替换段落文本 |
| | | * |
| | | * @param document docx解析对象 |
| | | * @param textMap 需要替换的信息集合 |
| | | */ |
| | | public static void changeText(XWPFDocument document, Map<String, String> textMap) { |
| | | // 获取段落集合 |
| | | List<XWPFTable> tables = document.getTables(); |
| | | for (XWPFTable table : tables) { |
| | | if (checkText(table.getText())) { |
| | | List<XWPFTableRow> rows = table.getRows(); |
| | | for (XWPFTableRow row : rows) { |
| | | List<XWPFTableCell> tableCells = row.getTableCells(); |
| | | for (XWPFTableCell cell : tableCells) { |
| | | if (checkText(cell.getText())) { |
| | | List<XWPFParagraph> paragraphs = cell.getParagraphs(); |
| | | for (XWPFParagraph paragraph : paragraphs) { |
| | | // 判断此段落时候需要进行替换 |
| | | String text = paragraph.getText(); |
| | | if (checkText(text)) { |
| | | List<XWPFRun> runs = paragraph.getRuns(); |
| | | for (XWPFRun run : runs) { |
| | | // 替换模板原来位置 |
| | | if (checkText(run.toString())) { |
| | | run.setText(changeValue(paragraph.getText(), textMap), 0); |
| | | } else { |
| | | run.setText("", 0); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 判断文本中时候包含$ |
| | | * |
| | | * @param text 文本 |
| | | * @return 包含返回true, 不包含返回false |
| | | */ |
| | | public static boolean checkText(String text) { |
| | | boolean check = false; |
| | | if (text.contains("$")) { |
| | | check = true; |
| | | } |
| | | return check; |
| | | } |
| | | |
| | | /** |
| | | * 匹配传入信息集合与模板 |
| | | * |
| | | * @param value 模板需要替换的区域 |
| | | * @param textMap 传入信息集合 |
| | | * @return 模板需要替换区域信息集合对应值 |
| | | */ |
| | | public static String changeValue(String value, Map<String, String> textMap) { |
| | | Set<Map.Entry<String, String>> textSets = textMap.entrySet(); |
| | | for (Map.Entry<String, String> textSet : textSets) { |
| | | // 匹配模板与替换值 格式${key} |
| | | String key = "${" + textSet.getKey() + "}"; |
| | | if (key.contains(value)) { |
| | | value = textSet.getValue(); |
| | | } |
| | | } |
| | | return value; |
| | | } |
| | | |
| | | /** |
| | | * 为表格插入数据,行数不够添加新行 |
| | | * |
| | | * @param table 需要插入数据的表格 |
| | | * @param tableList 插入数据集合 |
| | | */ |
| | | public static void insertTable(XWPFTable table, List<String[]> tableList) { |
| | | // 记录需要插入的第一行 |
| | | int start = -1; |
| | | for (int i = 0; i < table.getRows().size(); i++) { |
| | | for (int j = 0; j < table.getRows().get(i).getTableCells().size(); j++) { |
| | | if ("".equals(table.getRows().get(i).getTableCells().get(j).getText())) { |
| | | start = i; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | // 创建行,根据需要插入的数据添加新行 |
| | | if (start != -1) { |
| | | for (int i = 1; i < tableList.size(); i++) { |
| | | insertRow(table, start, start + i); |
| | | } |
| | | } |
| | | |
| | | // 遍历表格插入数据 |
| | | List<XWPFTableRow> rows = table.getRows(); |
| | | for (int i = start; i < rows.size(); i++) { |
| | | List<XWPFTableCell> cells = rows.get(i).getTableCells(); |
| | | for (int j = 0; j < table.getRow(start).getTableCells().size(); j++) { |
| | | XWPFTableCell cell = cells.get(j); |
| | | cell.setText(tableList.get(0)[j]); |
| | | } |
| | | tableList.remove(0); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 为表格插入数据,行数不够添加新行 |
| | | * |
| | | * @param table 需要插入数据的表格 |
| | | * @param copyRowIndex 复制行号 |
| | | * @param newRowIndex 新行号 |
| | | */ |
| | | public static void insertRow(XWPFTable table, int copyRowIndex, int newRowIndex) { |
| | | // 在表格中指定的位置新增一行 |
| | | XWPFTableRow targetRow = table.insertNewTableRow(newRowIndex); |
| | | |
| | | // 获取需要复制行对象 |
| | | XWPFTableRow copyRow = table.getRow(copyRowIndex); |
| | | |
| | | // 复制行对象 |
| | | targetRow.getCtRow().setTrPr(copyRow.getCtRow().getTrPr()); |
| | | //或许需要复制的行的列 |
| | | List<XWPFTableCell> copyCells = copyRow.getTableCells(); |
| | | // 复制列对象 |
| | | XWPFTableCell targetCell = null; |
| | | for (XWPFTableCell copyCell : copyCells) { |
| | | targetCell = targetRow.addNewTableCell(); |
| | | targetCell.getCTTc().setTcPr(copyCell.getCTTc().getTcPr()); |
| | | if (copyCell.getParagraphs() != null && copyCell.getParagraphs().size() > 0) { |
| | | targetCell.getParagraphs().get(0).getCTP().setPPr(copyCell.getParagraphs().get(0).getCTP().getPPr()); |
| | | if (copyCell.getParagraphs().get(0).getRuns() != null |
| | | && copyCell.getParagraphs().get(0).getRuns().size() > 0) { |
| | | XWPFRun cellR = targetCell.getParagraphs().get(0).createRun(); |
| | | cellR.setBold(copyCell.getParagraphs().get(0).getRuns().get(0).isBold()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 处理所有文段数据,除了表格 |
| | |
| | | /** |
| | | * 处理表格数据方法 |
| | | */ |
| | | public static void handleTable(XWPFDocument xwpfDocument, Map<String, String> insertTextMap, List<String[]> addList) { |
| | | public static void handleTable(XWPFDocument xwpfDocument, Map<String, String> map, List<String[]> addList) { |
| | | List<XWPFTable> tables = xwpfDocument.getTables(); |
| | | for (XWPFTable table : tables) { |
| | | List<XWPFTableRow> rows = table.getRows(); |
| | |
| | | } |
| | | |
| | | if (isReplacement(table.getText())) { |
| | | // 替换数据 |
| | | for (XWPFTableRow row : rows) { |
| | | List<XWPFTableCell> tableCells = row.getTableCells(); |
| | | for (XWPFTableCell tableCell : tableCells) { |
| | | if (isReplacement(tableCell.getText())) { |
| | | List<XWPFParagraph> paragraphs = tableCell.getParagraphs(); |
| | | for (XWPFParagraph paragraph : paragraphs) { |
| | | List<XWPFRun> runs = paragraph.getRuns(); |
| | | for (XWPFRun run : runs) { |
| | | run.setText(matchesValue(tableCell.getText(), insertTextMap), 0); |
| | | } |
| | | } |
| | | if (null == map || map.isEmpty()) { |
| | | continue; |
| | | } |
| | | |
| | | replaceData(rows, map); |
| | | } else { |
| | | insertData(table, addList); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 替换数据 |
| | | */ |
| | | private static void replaceData(List<XWPFTableRow> rows, Map<String, String> map) { |
| | | for (XWPFTableRow row : rows) { |
| | | List<XWPFTableCell> tableCells = row.getTableCells(); |
| | | for (XWPFTableCell tableCell : tableCells) { |
| | | if (isReplacement(tableCell.getText())) { |
| | | List<XWPFParagraph> paragraphs = tableCell.getParagraphs(); |
| | | for (XWPFParagraph paragraph : paragraphs) { |
| | | List<XWPFRun> runs = paragraph.getRuns(); |
| | | for (XWPFRun run : runs) { |
| | | run.setText(matchesValue(tableCell.getText(), map), 0); |
| | | } |
| | | } |
| | | } |
| | | } else { |
| | | // 插入数据 |
| | | for (int i = 1; i < addList.size(); i++) { |
| | | XWPFTableRow row = table.createRow(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | List<XWPFTableRow> rowList = table.getRows(); |
| | | for (int i = 1; i < rowList.size(); i++) { |
| | | XWPFTableRow xwpfTableRow = rowList.get(i); |
| | | List<XWPFTableCell> tableCells = xwpfTableRow.getTableCells(); |
| | | for (int j = 0; j < tableCells.size(); j++) { |
| | | XWPFTableCell xwpfTableCell = tableCells.get(j); |
| | | xwpfTableCell.setText(addList.get(i - 1)[j]); |
| | | } |
| | | /** |
| | | * 插入数据 |
| | | */ |
| | | private static void insertData(XWPFTable table, List<String[]> addList) { |
| | | for (int i = 1, c = addList.size(); i < c; i++) { |
| | | table.createRow(); |
| | | } |
| | | |
| | | List<XWPFTableCell> oldCells = table.getRow(1).getTableCells(); |
| | | List<XWPFTableRow> rowList = table.getRows(); |
| | | for (int i = 0, c = addList.size(); i < c; i++) { |
| | | XWPFTableRow xwpfTableRow = rowList.get(i + 1); |
| | | |
| | | List<XWPFTableCell> tableCells = xwpfTableRow.getTableCells(); |
| | | for (int j = 0; j < tableCells.size(); j++) { |
| | | XWPFTableCell oldCell = oldCells.get(j); |
| | | XWPFTableCell newCell = tableCells.get(j); |
| | | |
| | | if (0 == i) { |
| | | // newCell.setText(addList.get(i)[j]) |
| | | setCellText(newCell, addList.get(i)[j]); |
| | | } else { |
| | | setCellText(oldCell, newCell, addList.get(i)[j]); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 设置单元格文本 |
| | | */ |
| | | private static void setCellText(XWPFTableCell cell, String text) { |
| | | List<XWPFParagraph> paragraphs = cell.getParagraphs(); |
| | | for (XWPFParagraph paragraph : paragraphs) { |
| | | List<XWPFRun> runs = paragraph.getRuns(); |
| | | for (XWPFRun run : runs) { |
| | | run.setText(text, 0); |
| | | } |
| | | } |
| | | } |
| | |
| | | public static String matchesValue(String wordValue, Map<String, String> map) { |
| | | for (String s : map.keySet()) { |
| | | String s1 = "${" + s + "}"; |
| | | if (s1.equals(wordValue)) { |
| | | /*if (s1.equals(wordValue)) { |
| | | wordValue = map.get(s); |
| | | }*/ |
| | | if (wordValue.contains(s1)) { |
| | | wordValue = wordValue.replace(s1, map.get(s)); |
| | | } |
| | | } |
| | | |
| | |
| | | * 测试是否包含需要替换的数据 |
| | | */ |
| | | public static boolean isReplacement(String text) { |
| | | return text.contains("$"); |
| | | return text.contains("${"); |
| | | } |
| | | |
| | | /** |
| | | * 复制模板行的属性 |
| | | */ |
| | | private static void setCellText(XWPFTableCell tmpCell, XWPFTableCell cell, String text) { |
| | | CTTc cttc2 = tmpCell.getCTTc(); |
| | | CTTcPr ctPr2 = cttc2.getTcPr(); |
| | | CTTc cttc = cell.getCTTc(); |
| | | CTTcPr ctPr = cttc.addNewTcPr(); |
| | | if (ctPr2.getTcW() != null) { |
| | | ctPr.addNewTcW().setW(ctPr2.getTcW().getW()); |
| | | } |
| | | if (ctPr2.getVAlign() != null) { |
| | | ctPr.addNewVAlign().setVal(ctPr2.getVAlign().getVal()); |
| | | } |
| | | if (ctPr2.getTcBorders() != null) { |
| | | ctPr.setTcBorders(ctPr2.getTcBorders()); |
| | | } |
| | | |
| | | XWPFParagraph tmpP = tmpCell.getParagraphs().get(0); |
| | | XWPFParagraph cellP = cell.getParagraphs().get(0); |
| | | XWPFRun tmpR = null; |
| | | if (tmpP.getRuns() != null && tmpP.getRuns().size() > 0) { |
| | | tmpR = tmpP.getRuns().get(0); |
| | | } |
| | | XWPFRun cellR = cellP.createRun(); |
| | | cellR.setText(text); |
| | | |
| | | // 复制字体信息 |
| | | copyFontInfo(cellR, tmpR); |
| | | |
| | | // 复制段落信息 |
| | | cellP.setAlignment(tmpP.getAlignment()); |
| | | cellP.setVerticalAlignment(tmpP.getVerticalAlignment()); |
| | | cellP.setBorderBetween(tmpP.getBorderBetween()); |
| | | cellP.setBorderBottom(tmpP.getBorderBottom()); |
| | | cellP.setBorderLeft(tmpP.getBorderLeft()); |
| | | cellP.setBorderRight(tmpP.getBorderRight()); |
| | | cellP.setBorderTop(tmpP.getBorderTop()); |
| | | cellP.setPageBreak(tmpP.isPageBreak()); |
| | | |
| | | if (tmpP.getCTP() != null && tmpP.getCTP().getPPr() != null) { |
| | | CTPPr tmpPpr = tmpP.getCTP().getPPr(); |
| | | CTPPr cellPpr = cellP.getCTP().getPPr() != null ? cellP.getCTP().getPPr() : cellP.getCTP().addNewPPr(); |
| | | |
| | | // 复制段落间距信息 |
| | | copySpacing(tmpPpr, cellPpr); |
| | | |
| | | // 复制段落缩进信息 |
| | | copyParagraph(tmpPpr, cellPpr); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 复制字体信息 |
| | | */ |
| | | private static void copyFontInfo(XWPFRun cellR, XWPFRun tmpR) { |
| | | if (tmpR == null) { |
| | | return; |
| | | } |
| | | if (!cellR.isBold()) { |
| | | cellR.setBold(tmpR.isBold()); |
| | | } |
| | | cellR.setItalic(tmpR.isItalic()); |
| | | cellR.setUnderline(tmpR.getUnderline()); |
| | | cellR.setColor(tmpR.getColor()); |
| | | cellR.setTextPosition(tmpR.getTextPosition()); |
| | | if (tmpR.getFontSize() != -1) { |
| | | cellR.setFontSize(tmpR.getFontSize()); |
| | | } |
| | | if (tmpR.getFontFamily() != null) { |
| | | cellR.setFontFamily(tmpR.getFontFamily()); |
| | | } |
| | | if (tmpR.getCTR() != null) { |
| | | if (tmpR.getCTR().isSetRPr()) { |
| | | CTRPr tmpRpr = tmpR.getCTR().getRPr(); |
| | | if (tmpRpr.isSetRFonts()) { |
| | | CTFonts tmpFonts = tmpRpr.getRFonts(); |
| | | CTRPr cellRpr = cellR.getCTR().isSetRPr() ? cellR.getCTR().getRPr() : cellR.getCTR().addNewRPr(); |
| | | CTFonts cellFonts = cellRpr.isSetRFonts() ? cellRpr.getRFonts() : cellRpr.addNewRFonts(); |
| | | cellFonts.setAscii(tmpFonts.getAscii()); |
| | | cellFonts.setAsciiTheme(tmpFonts.getAsciiTheme()); |
| | | cellFonts.setCs(tmpFonts.getCs()); |
| | | cellFonts.setCstheme(tmpFonts.getCstheme()); |
| | | cellFonts.setEastAsia(tmpFonts.getEastAsia()); |
| | | cellFonts.setEastAsiaTheme(tmpFonts.getEastAsiaTheme()); |
| | | cellFonts.setHAnsi(tmpFonts.getHAnsi()); |
| | | cellFonts.setHAnsiTheme(tmpFonts.getHAnsiTheme()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 复制段落间距信息 |
| | | */ |
| | | private static void copySpacing(CTPPr tmpPpr, CTPPr cellPpr) { |
| | | CTSpacing tmpSpacing = tmpPpr.getSpacing(); |
| | | if (tmpSpacing != null) { |
| | | CTSpacing cellSpacing = cellPpr.getSpacing() != null ? cellPpr.getSpacing() : cellPpr.addNewSpacing(); |
| | | if (tmpSpacing.getAfter() != null) { |
| | | cellSpacing.setAfter(tmpSpacing.getAfter()); |
| | | } |
| | | if (tmpSpacing.getAfterAutospacing() != null) { |
| | | cellSpacing.setAfterAutospacing(tmpSpacing.getAfterAutospacing()); |
| | | } |
| | | if (tmpSpacing.getAfterLines() != null) { |
| | | cellSpacing.setAfterLines(tmpSpacing.getAfterLines()); |
| | | } |
| | | if (tmpSpacing.getBefore() != null) { |
| | | cellSpacing.setBefore(tmpSpacing.getBefore()); |
| | | } |
| | | if (tmpSpacing.getBeforeAutospacing() != null) { |
| | | cellSpacing.setBeforeAutospacing(tmpSpacing |
| | | .getBeforeAutospacing()); |
| | | } |
| | | if (tmpSpacing.getBeforeLines() != null) { |
| | | cellSpacing.setBeforeLines(tmpSpacing.getBeforeLines()); |
| | | } |
| | | if (tmpSpacing.getLine() != null) { |
| | | cellSpacing.setLine(tmpSpacing.getLine()); |
| | | } |
| | | if (tmpSpacing.getLineRule() != null) { |
| | | cellSpacing.setLineRule(tmpSpacing.getLineRule()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 复制段落缩进信息 |
| | | */ |
| | | private static void copyParagraph(CTPPr tmpPpr, CTPPr cellPpr) { |
| | | CTInd tmpInd = tmpPpr.getInd(); |
| | | if (tmpInd != null) { |
| | | CTInd cellInd = cellPpr.getInd() != null ? cellPpr.getInd() : cellPpr.addNewInd(); |
| | | if (tmpInd.getFirstLine() != null) { |
| | | cellInd.setFirstLine(tmpInd.getFirstLine()); |
| | | } |
| | | if (tmpInd.getFirstLineChars() != null) { |
| | | cellInd.setFirstLineChars(tmpInd.getFirstLineChars()); |
| | | } |
| | | if (tmpInd.getHanging() != null) { |
| | | cellInd.setHanging(tmpInd.getHanging()); |
| | | } |
| | | if (tmpInd.getHangingChars() != null) { |
| | | cellInd.setHangingChars(tmpInd.getHangingChars()); |
| | | } |
| | | if (tmpInd.getLeft() != null) { |
| | | cellInd.setLeft(tmpInd.getLeft()); |
| | | } |
| | | if (tmpInd.getLeftChars() != null) { |
| | | cellInd.setLeftChars(tmpInd.getLeftChars()); |
| | | } |
| | | if (tmpInd.getRight() != null) { |
| | | cellInd.setRight(tmpInd.getRight()); |
| | | } |
| | | if (tmpInd.getRightChars() != null) { |
| | | cellInd.setRightChars(tmpInd.getRightChars()); |
| | | } |
| | | } |
| | | } |
| | | } |