以下都是借鉴网上内容:
环境 纯后端, java, spring项目 maven管理.
maven内容:
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.16</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-scratchpad</artifactId><version>3.16</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>ooxml-schemas</artifactId><version>1.3</version></dependency>
运行时候如果报错: XmlOptions.setEntityExpansionLimit ( ) 方法找不到,那就是xmlbeans版本太低 升级以下:
就可以解决找不到方法:问题 如果没报错 ( 就把改依赖忽略),
<dependency><groupId>org.apache.xmlbeans</groupId><artifactId>xmlbeans</artifactId><version>3.1.0</version></dependency>
代码如下 工具类一 :
package com.bsoft.hesp.utils.word;import java.util.*;import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;public class WordExportUtil {private WordExportUtil() {}/*** 替换文档中段落文本** @param document docx解析对象* @param textMap 需要替换的信息集合*/public static void changeParagraphText(XWPFDocument document, Map<String, String> textMap) {//获取段落集合List<XWPFParagraph> paragraphs = document.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {//判断此段落是否需要进行替换String text = paragraph.getText();if (checkText(text)) {List<XWPFRun> runs = paragraph.getRuns();for (XWPFRun run : runs) {//替换模板原来位置String textValue = changeValue(run.toString(), textMap);if (run.toString().toLowerCase().indexOf("checkbox_") != -1) {// 复选框填充值run.setFontFamily("SimSun");String[] tArr = textValue.split("@@@");for (int i = 0; i < tArr.length; i++) {if (i == 0) {run.setText(tArr[i], 0);} else {run.setText(tArr[i]);}if (i != tArr.length - 1) {run.addBreak();//换行}}} else {run.setText(textValue, 0);}}}}}/*** 复制表头 插入行数据,这里样式和表头一样** @param document docx解析对象* @param tableList 需要插入数据集合* tableIndex表格索引,在word表格对象集合中是第几个表格,从0开始* @param headerIndex 表头的行索引,从0开始*/public static void copyHeaderInsertText(XWPFDocument document, List<Map<String, String>> tableList, String[] fields, int tableindex, int headerIndex) {if (null == tableList || null == fields) {return;}//获取表格对象集合List<XWPFTable> tables = document.getTables();XWPFTableRow copyRow = tables.get(tableindex).getRow(headerIndex);List<XWPFTableCell> cellList = copyRow.getTableCells();if (null == cellList) {return;}//遍历要添加的数据的listfor (int i = 0; i < tableList.size(); i++) {//插入一行XWPFTableRow targetRow = tables.get(tableindex).insertNewTableRow(headerIndex + i);//复制行属性targetRow.getCtRow().setTrPr(copyRow.getCtRow().getTrPr());Map<String, String> map = tableList.get(i);// 字段匹配后,插入单元格并赋值for (String field : fields) {int idx = 0;for (Map.Entry<String, String> entry : map.entrySet()) {if (!field.equals(entry.getKey())) continue;XWPFTableCell sourceCell = cellList.get(idx);//插入一个单元格XWPFTableCell targetCell = targetRow.addNewTableCell();//复制列属性targetCell.getCTTc().setTcPr(sourceCell.getCTTc().getTcPr());//targetCell.setText(entry.getValue());/** XWPFTableCell 无法直接设置字体样式,故换一种方式 **///获取 XWPFTableCell 的CTTcCTTc ctTc = targetCell.getCTTc();//获取 CTPCTP ctP = (ctTc.sizeOfPArray() == 0) ? ctTc.addNewP() : ctTc.getPArray(0);//getParagraph(ctP) 获取 XWPFParagraphXWPFParagraph par = targetCell.getParagraph(ctP);//XWPFRun 设置格式XWPFRun run = par.createRun();String textValue = entry.getValue();// 复选框填充值if (field.toLowerCase().indexOf("checkbox_") != -1) {run.setFontFamily("SimSun");String[] tArr = textValue.split("@@@");for (int j = 0; j < tArr.length; j++) {if (j == 0) {run.setText(tArr[j], 0);} else {run.setText(tArr[j]);}if (j != tArr.length - 1) {run.addBreak();//换行}}} else {run.setText(textValue, 0);}idx++;};}}if (tableList.size() > 0) {List<XWPFTableRow> rows = tables.get(tableindex).getRows();int rowLength = rows.size();deleteTable(tables.get(tableindex), tableList.size() + headerIndex, rowLength);}}/*** 删除表格行** @param table 表格对象* @param fromIndex 从第几行,从0开始* @param toIndex 到第几行,从0开始*/public static void deleteTable(XWPFTable table, int fromIndex, int toIndex) {for (int i = fromIndex; i < toIndex; i++) {table.removeRow(fromIndex);}}/*** 替换表格对象方法** @param document docx解析对象* @param textMap 需要替换的信息集合*/public static void changeTableText(XWPFDocument document, Map<String, String> textMap) {//获取表格对象集合List<XWPFTable> tables = document.getTables();for (int i = 0; i < tables.size(); i++) {//只处理行数大于等于2的表格XWPFTable table = tables.get(i);/*if (table.getRows().size() > 1) {//判断表格是需要替换还是需要插入,判断逻辑有$为替换if (checkText(table.getText())) {List<XWPFTableRow> rows = table.getRows();//遍历表格,并替换模板eachTable(rows, textMap);}}*///判断表格是需要替换还是需要插入,判断逻辑有$为替换if (checkText(table.getText())) {List<XWPFTableRow> rows = table.getRows();//遍历表格,并替换模板eachTable(rows, textMap);}}}/*** 遍历表格,并替换模板** @param rows 表格行对象* @param textMap 需要替换的信息集合*/public static void eachTable(List<XWPFTableRow> rows, Map<String, String> textMap) {for (XWPFTableRow row : rows) {List<XWPFTableCell> cells = row.getTableCells();for (XWPFTableCell cell : cells) {//判断单元格是否需要替换if (checkText(cell.getText())) {List<XWPFParagraph> paragraphs = cell.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {List<XWPFRun> runs = paragraph.getRuns();for (XWPFRun run : runs) {fillCheckBox(run, textMap);}}}}}}public static void fillCheckBox(XWPFRun run, Map<String, String> textMap) {String textValue = changeValue(run.toString(), textMap);if (run.toString().toLowerCase().indexOf("checkbox_") != -1) {// 复选框填充值run.setFontFamily("SimSun");String[] tArr = textValue.split("@@@");for (int i = 0; i < tArr.length; i++) {if (i == 0) {run.setText(tArr[i], 0);} else {run.setText(tArr[i]);}/*if (i != tArr.length - 1) {run.addBreak();//换行}*/}} else {run.setText(textValue, 0);}}/*** 匹配传入信息集合与模板** @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 (value.indexOf(key) != -1) {value = textSet.getValue();}}//模板未匹配到区域替换为空if (checkText(value)) {value = "";}return value;}/*** 判断文本中是否包含$** @param text 文本* @return 包含返回true, 不包含返回false*/public static boolean checkText(String text) {boolean check = false;if (text.indexOf("$") != -1) {check = true;}return check;}
}
package com.bsoft.hesp.utils.word;import org.apache.http.HttpHeaders;
import org.apache.poi.xwpf.usermodel.XWPFDocument;import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;/*** Author: * Date: 2023/11/27 15:05**/
public class WordGenerate {/*** word生成* @throws FileNotFoundException*/public static void generateWord(List<Map<String, String>> list, Map<String, String> fileAddress, HttpServletResponse response) throws FileNotFoundException {XWPFDocument document = null;try {for (Map<String, String> tableMap : list) {String classpath = WordGenerate.class.getResource("").getPath();File f = new File(classpath+"/模板20231124.docx");FileInputStream fileInputStream = new FileInputStream(new File(f.getPath()));FileOutputStream fileOutStream = new FileOutputStream("E:\\" + tableMap.get("fileName") + ".docx");try {/**解析docx模板并获取document对象**/document = new XWPFDocument(fileInputStream);/**替换docx table中文本字段**/WordExportUtil.changeTableText(document, tableMap);document.write(fileOutStream);} catch (IOException e) {e.printStackTrace();} finally {if (document != null) {try {document.close();} catch (IOException e) {e.printStackTrace();}}if (null != fileInputStream) {try {fileInputStream.close();} catch (IOException e) {e.printStackTrace();}}if (null != fileOutStream) {try {fileOutStream.close();} catch (IOException e) {e.printStackTrace();}}}}} catch (Exception e) {e.printStackTrace();}}
}