以下都是借鉴网上内容:
环境 纯后端, 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;
}
//遍历要添加的数据的list
for (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 的CTTc
CTTc ctTc = targetCell.getCTTc();
//获取 CTP
CTP ctP = (ctTc.sizeOfPArray() == 0) ? ctTc.addNewP() : ctTc.getPArray(0);
//getParagraph(ctP) 获取 XWPFParagraph
XWPFParagraph 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 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();
}
}
}