给你提供一种思路,使用word模版,然后通过poi根据模版生成文件,我给你提供的demo,poi jar包的版本是5.0.0。希望对你有用。
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.CTTbl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblGrid;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class WordTemplateUtil {
private static Log logger = LogFactory.getLog(WordTemplateUtil.class);
private static final String PREFIX = "{";
private static final String SUFFIX = "}";
private XWPFDocument document;
public XWPFDocument getDocument() {
return document;
}
public void setDocument(XWPFDocument document) {
this.document = document;
}
/**
* 初始化模板内容
*
* @param inputStream 模板的读取流(docx文件)
* @throws IOException
*/
public WordTemplateUtil(InputStream inputStream) throws IOException {
document = new XWPFDocument(inputStream);
}
/**
* 将处理后的内容写入到输出流中
*
* @param outputStream
* @throws IOException
*/
public void write(OutputStream outputStream) throws IOException {
document.write(outputStream);
}
/**
* 根据dataMap对word文件中的标签进行替换; <br><br>
* !!!!***需要注意dataMap的数据格式***!!!! <br><br>
* 对于需要替换的普通标签数据标签(不需要循环)-----必须在dataMap中存储一个key为parametersMap的map,
* 来存储这些不需要循环生成的数据,比如:表头信息,日期,制表人等。 <br><br>
* 对于需要循环生成的表格数据------key自定义,value为 --ArrayList<Map<String, String>>
*
* @param dataMap
*/
public void replaceDocument(Map<String, Object> dataMap) {
if (!dataMap.containsKey("paramsMap")) {
logger.info("数据源错误--数据源(paramsMap)缺失");
return;
}
@SuppressWarnings("unchecked")
Map<String, Object> paramsMap = (Map<String, Object>) dataMap.get("paramsMap");
// 所有对象(段落+表格)
List<IBodyElement> bodyElements = document.getBodyElements();
// 标记模板文件(段落+表格)总个数
int templateBodySize = bodyElements.size();
// 当前操作表格对象的索引
int curT = 0;
// 当前操作段落对象的索引
int curP = 0;
for (int a = 0; a < templateBodySize; a++) {
IBodyElement body = bodyElements.get(a);
if (BodyElementType.TABLE.equals(body.getElementType())) {
// 处理表格
XWPFTable table = body.getBody().getTableArray(curT);
List<XWPFTable> tables = body.getBody().getTables();
table = tables.get(curT);
if (table != null) {
// 处理表格
List<XWPFTableCell> tableCells = table.getRows().get(0).getTableCells();
// 获取到模板表格第一行,用来判断表格类型
String tableText = table.getText();
// 表格中的所有文本
if (tableText.indexOf("##{foreach") > -1) {
// 查找到##{foreach标签,该表格需要处理循环
if (tableCells.size() != 2 || tableCells.get(0).getText().indexOf("##{foreach") < 0 || tableCells.get(0).getText().trim().length() == 0) {
logger.info("文档中第" + (curT + 1) + "个表格模板错误,模板表格第一行需要设置2个单元格," + "第一个单元格存储表格类型(##{foreachTable}## 或者 ##{foreachTableRow}##),第二个单元格定义数据源。");
return;
}
String tableType = tableCells.get(0).getText();
String dataSource = tableCells.get(1).getText();
if (!dataMap.containsKey(dataSource)) {
logger.info("文档中第" + (curT + 1) + "个表格模板数据源缺失");
return;
}
@SuppressWarnings("unchecked")
List<Map<String, Object>> tableDataList = (List<Map<String, Object>>) dataMap.get(dataSource);
if ("##{foreachTable}##".equals(tableType)) {
addTableInDocFooter(table, tableDataList, paramsMap, 1);
} else if ("##{foreachTableRow}##".equals(tableType)) {
addTableInDocFooter(table, tableDataList, paramsMap, 2);
}
} else if (tableText.indexOf(PREFIX) > -1) {
// 没有查找到##{foreach标签,查找到了普通替换数据的{}标签,该表格只需要简单替换
addTableInDocFooter(table, null, paramsMap, 3);
} else {
// 没有查找到任何标签,该表格是一个静态表格,仅需要复制一个即可。
addTableInDocFooter(table, null, null, 0);
}
curT++;
}
} else if (BodyElementType.PARAGRAPH.equals(body.getElementType())) {
// 处理段落
XWPFParagraph ph = body.getBody().getParagraphArray(curP);
if (ph != null) {
//htmlText = htmlText + readParagraphX(ph);
addParagraphInDocFooter(ph, null, paramsMap, 0);
curP++;
}
}
}
// 处理完毕模板,删除文本中的模板内容
for (int a = 0; a < templateBodySize; a++) {
document.removeBodyElement(0);
}
}
/**
* }
* }
* }
* <p>
* /*根据 模板表格 和 数据list 在word文档末尾生成表格
*
* @param templateTable 模板表格
* @param list 循环数据集
* @param paramsMap 不循环数据集
* @param flag(0为静态表格,1为表格整体循环,2为表格内部行循环,3为表格不循环仅简单替换标签即可)
*/
public void addTableInDocFooter(XWPFTable templateTable, List<Map<String, Object>> list, Map<String, Object> paramsMap, int flag) {
if (flag == 1) {
// 表格整体循环
for (Map<String, Object> map : list) {
// 获取模板表格所有行
List<XWPFTableRow> templateTableRows = templateTable.getRows();
// 创建新表格,默认一行一列
XWPFTable newCreateTable = document.createTable();
CTTbl ctTbl = newCreateTable.getCTTbl();
ctTbl.getTblPr().set(templateTable.getCTTbl().getTblPr());
if(templateTable.getCTTbl() != null){
CTTblGrid cg = ctTbl.addNewTblGrid();
cg.addNewGridCol().set(templateTable.getCTTbl().getTblGrid());
}
for (int i = 1; i < templateTableRows.size(); i++) {
XWPFTableRow newCreateRow = newCreateTable.createRow();
// 复制模板行文本和样式到新行
copyTableRow(newCreateRow, templateTableRows.get(i));
}
// 移除多出来的第一行
newCreateTable.removeRow(0);
//替换标签
replaceTable(newCreateTable, map);
}
} else if (flag == 2) {
// 表格表格内部行循环
XWPFTable newCreateTable = document.createTable();
List<XWPFTableRow> TempTableRows = templateTable.getRows();
// 获取模板表格所有行
int tagRowsIndex = 0;
// 标签行indexs
for (int i = 0, size = TempTableRows.size(); i < size; i++) {
String rowText = TempTableRows.get(i).getCell(0).getText();
// 获取到表格行的第一个单元格
if (rowText.contains("##{foreachRows}##")) {
tagRowsIndex = i;
break;
}
}
/* 复制模板行和标签行之前的行 */
for (int i = 1; i < tagRowsIndex; i++) {
XWPFTableRow newCreateRow = newCreateTable.createRow();
copyTableRow(newCreateRow, TempTableRows.get(i));
// 复制行
replaceTableRow(newCreateRow, paramsMap);
// 处理不循环标签的替换
}
/* 循环生成模板行 */
XWPFTableRow tempRow = TempTableRows.get(tagRowsIndex + 1);
// 获取到模板行
for (int i = 0; i < list.size(); i++) {
XWPFTableRow newCreateRow = newCreateTable.createRow();
copyTableRow(newCreateRow, tempRow);
// 复制模板行
replaceTableRow(newCreateRow, list.get(i));
// 处理标签替换
}
/* 复制模板行和标签行之后的行 */
for (int i = tagRowsIndex + 2; i < TempTableRows.size(); i++) {
XWPFTableRow newCreateRow = newCreateTable.createRow();
// 复制行
copyTableRow(newCreateRow, TempTableRows.get(i));
// 处理不循环标签的替换
replaceTableRow(newCreateRow, paramsMap);
}
// 移除多出来的第一行
newCreateTable.removeRow(0);
} else if (flag == 3) {
//表格不循环仅简单替换标签
XWPFTable newCreateTable = document.createTable();
// 获取模板表格所有行
List<XWPFTableRow> templateTableRows = templateTable.getRows();
CTTbl ctTbl = newCreateTable.getCTTbl();
ctTbl.getTblPr().set(templateTable.getCTTbl().getTblPr());
if(templateTable.getCTTbl() != null){
CTTblGrid cg = ctTbl.addNewTblGrid();
cg.addNewGridCol().set(templateTable.getCTTbl().getTblGrid());
}
for (int i = 0; i < templateTableRows.size(); i++) {
XWPFTableRow newCreateRow = newCreateTable.createRow();
// 复制模板行文本和样式到新行
copyTableRow(newCreateRow, templateTableRows.get(i));
}
// 移除多出来的第一行
newCreateTable.removeRow(0);
// 替换标签
replaceTable(newCreateTable, paramsMap);
} else if (flag == 0) {
// 获取模板表格所有行
List<XWPFTableRow> templateTableRows = templateTable.getRows();
// 创建新表格,默认一行一列
XWPFTable newCreateTable = document.createTable();
for (int i = 0; i < templateTableRows.size(); i++) {
XWPFTableRow newCreateRow = newCreateTable.createRow();
// 复制模板行文本和样式到新行
copyTableRow(newCreateRow, templateTableRows.get(i));
}
// 移除多出来的第一行
newCreateTable.removeRow(0);
}
}
/**
* }
* }
* <p>
* 根据 模板段落
* 和 数据
* 在文档末尾生成段落
*
* @param templateParagraph 模板段落
* @param list 循环数据集
* @param paramsMap 不循环数据集
* @param flag (0 为不循环替换,1 为循环替换)
*/
public void addParagraphInDocFooter(XWPFParagraph templateParagraph, List<Map<String, String>> list,
Map<String, Object> paramsMap,
int flag) {
if (flag == 0) {
XWPFParagraph createParagraph = document.createParagraph();
// 设置段落样式
createParagraph.getCTP().setPPr(templateParagraph.getCTP().getPPr());
// 移除原始内容
for (int pos = 0; pos < createParagraph.getRuns().size(); pos++) {
createParagraph.removeRun(pos);
}
// 添加Run标签
for (XWPFRun s : templateParagraph.getRuns()) {
XWPFRun targetrun = createParagraph.createRun();
CopyRun(targetrun, s);
}
replaceParagraph(createParagraph, paramsMap);
} else if (flag == 1) {
// 暂无实现
}
}
/**
* 根据map替换段落元素内的 {**} 标签
*
* @param xWPFParagraph
* @param paramsMap
*/
public void replaceParagraph(XWPFParagraph xWPFParagraph, Map<String, Object> paramsMap) {
List<XWPFRun> runs = xWPFParagraph.getRuns();
String xWPFParagraphText = xWPFParagraph.getText();
String regEx = "\\{.+?\\}";
Pattern pattern = Pattern.compile(regEx);
//正则匹配字符串{****}
Matcher matcher = pattern.matcher(xWPFParagraphText);
// 查找到有标签才执行替换
if (matcher.find()) {
// 标签开始run位置
int beginRunIndex = xWPFParagraph.searchText(PREFIX, new PositionInParagraph()).getBeginRun();
// 结束标签
int endRunIndex = xWPFParagraph.searchText(SUFFIX, new PositionInParagraph()).getEndRun();
StringBuffer key = new StringBuffer();
if (beginRunIndex == endRunIndex) {
// {**}在一个run标签内
XWPFRun beginRun = runs.get(beginRunIndex);
String beginRunText = beginRun.text();
int beginIndex = beginRunText.indexOf(PREFIX);
int endIndex = beginRunText.indexOf(SUFFIX);
int length = beginRunText.length();
if (beginIndex == 0 && endIndex == length - 1) {
// 该run标签只有{**}
XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex);
insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr());
// 设置文本
key.append(beginRunText.substring(1, endIndex));
insertNewRun.setText(getValueByKey(key.toString(), paramsMap));
xWPFParagraph.removeRun(beginRunIndex + 1);
} else {
// 该run标签为**{**}** 或者 **{**} 或者{**}**,替换key后,还需要加上原始key前后的文本
XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex);
insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr());
// 设置文本
key.append(beginRunText.substring(beginRunText.indexOf(PREFIX) + 1, beginRunText.indexOf(SUFFIX)));
String textString = beginRunText.substring(0, beginIndex) + getValueByKey(key.toString(), paramsMap) + beginRunText.substring(endIndex + 1);
insertNewRun.setText(textString);
xWPFParagraph.removeRun(beginRunIndex + 1);
}
} else {
// {**}被分成多个run //先处理起始run标签,取得第一个{key}值
XWPFRun beginRun = runs.get(beginRunIndex);
String beginRunText = beginRun.text();
int beginIndex = beginRunText.indexOf(PREFIX);
if (beginRunText.length() > 1) {
key.append(beginRunText.substring(beginIndex + 1));
}
//需要移除的run //处理中间的run
ArrayList<Integer> removeRunList = new ArrayList<>();
for (int i = beginRunIndex + 1; i < endRunIndex; i++) {
XWPFRun run = runs.get(i);
String runText = run.text();
key.append(runText);
removeRunList.add(i);
}
// 获取endRun中的key值
XWPFRun endRun = runs.get(endRunIndex);
String endRunText = endRun.text();
int endIndex = endRunText.indexOf(SUFFIX);
//run中**}或者**}**
if (endRunText.length() > 1 && endIndex != 0) {
key.append(endRunText.substring(0, endIndex));
}
//*******************************************************************
// 取得key值后替换标签
// 先处理开始标签
if (beginRunText.length() == 2) {
// run标签内文本{
XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex);
insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr());
// 设置文本
insertNewRun.setText(getValueByKey(key.toString(), paramsMap));
//移除原始的run
xWPFParagraph.removeRun(beginRunIndex + 1);
} else {
// 该run标签为**{**或者 {** ,替换key后,还需要加上原始key前的文本
XWPFRun insertNewRun = xWPFParagraph.insertNewRun(beginRunIndex);
insertNewRun.getCTR().setRPr(beginRun.getCTR().getRPr());
// 设置文本
String textString = beginRunText.substring(0, beginRunText.indexOf(PREFIX)) + getValueByKey(key.toString(), paramsMap);
insertNewRun.setText(textString);
//移除原始的run
xWPFParagraph.removeRun(beginRunIndex + 1);
}
//处理结束标签
if (endRunText.length() == 1) {
// run标签内文本只有}
XWPFRun insertNewRun = xWPFParagraph.insertNewRun(endRunIndex);
insertNewRun.getCTR().setRPr(endRun.getCTR().getRPr());
// 设置文本
insertNewRun.setText("");
//移除原始的run
xWPFParagraph.removeRun(endRunIndex + 1);
} else {
// 该run标签为**}**或者 }** 或者**},替换key后,还需要加上原始key后的文本
XWPFRun insertNewRun = xWPFParagraph.insertNewRun(endRunIndex);
insertNewRun.getCTR().setRPr(endRun.getCTR().getRPr());
// 设置文本
String textString = endRunText.substring(endRunText.indexOf(SUFFIX) + 1);
insertNewRun.setText(textString);
//移除原始的run
xWPFParagraph.removeRun(endRunIndex + 1);
} //处理中间的run标签
for (int i = 0; i < removeRunList.size(); i++) {
XWPFRun xWPFRun = runs.get(removeRunList.get(i));
//原始run
XWPFRun insertNewRun = xWPFParagraph.insertNewRun(removeRunList.get(i));
insertNewRun.getCTR().setRPr(xWPFRun.getCTR().getRPr());
insertNewRun.setText("");
xWPFParagraph.removeRun(removeRunList.get(i) + 1);
//移除原始的run
}
}
// 处理${**}被分成多个run
replaceParagraph(xWPFParagraph, paramsMap);
}
}
/**
* 替换文本列表,回车换行
* 待完善,现只支持替换标签在一个run中
*
* @param textListMap
*/
public void replaceParagraphList(Map<String, List<String>> textListMap) {
for (XWPFParagraph paragraph : document.getParagraphs()) {
String xWPFParagraphText = paragraph.getText();
for (Map.Entry<String, List<String>> entry : textListMap.entrySet()) {
if (!Pattern.compile(entry.getKey()).matcher(xWPFParagraphText).find()) {
continue;
}
// 找到填写run
Integer beginRunIndex = paragraph.searchText(entry.getKey(), new PositionInParagraph()).getBeginRun();
XWPFRun beginRun = paragraph.getRuns().get(beginRunIndex);
for (int i = 0; i < entry.getValue().size(); i++) {
String text = entry.getValue().get(i);
if (i == 0) {
XWPFRun addrRun = paragraph.insertNewRun(beginRunIndex + 1);
addrRun.getCTR().setRPr(beginRun.getCTR().getRPr());
addrRun.setText(text);
continue;
}
// 换行
XWPFRun newlineRun = paragraph.insertNewRun(beginRunIndex + i + 1);
newlineRun.addBreak(BreakType.TEXT_WRAPPING);
// 设置文本
XWPFRun addrRun = paragraph.insertNewRun(beginRunIndex + i + 2);
addrRun.getCTR().setRPr(beginRun.getCTR().getRPr());
addrRun.setText(text);
}
// 去除原数据
paragraph.removeRun(beginRunIndex);
}
}
}
/**
* 复制表格行XWPFTableRow格式
*
* @param target 待修改格式的XWPFTableRow
* @param source 模板XWPFTableRow
*/
public void copyTableRow(XWPFTableRow target, XWPFTableRow source) {
int tempRowCellsize = source.getTableCells().size();
// 模板行的列数
for (int i = 0; i < tempRowCellsize - 1; i++) {
// 为新添加的行添加与模板表格对应行行相同个数的单元格
target.addNewTableCell();
}
// 复制样式
target.getCtRow().setTrPr(source.getCtRow().getTrPr());
// 复制单元格
for (int i = 0; i < target.getTableCells().size(); i++) {
copyTableCell(target.getCell(i), source.getCell(i));
}
}
/**
* 复制单元格XWPFTableCell格式
*
* @param newTableCell 新创建的的单元格
* @param templateTableCell 模板单元格
*/
private void copyTableCell(XWPFTableCell newTableCell, XWPFTableCell templateTableCell) {
// 列属性
newTableCell.getCTTc().setTcPr(templateTableCell.getCTTc().getTcPr());
// 删除目标
// targetCell 所有文本段落
for (int pos = 0; pos < newTableCell.getParagraphs().size(); pos++) {
newTableCell.removeParagraph(pos);
}
// 添加新文本段落
for (XWPFParagraph sp : templateTableCell.getParagraphs()) {
XWPFParagraph targetP = newTableCell.addParagraph();
copyParagraph(targetP, sp);
}
}
/**
* 复制文本段落XWPFParagraph格式
*
* @param newParagraph 新创建的的段落
* @param templateParagraph 模板段落
*/
private void copyParagraph(XWPFParagraph newParagraph, XWPFParagraph templateParagraph) {
// 设置段落样式
newParagraph.getCTP().setPPr(templateParagraph.getCTP().getPPr());
// 添加Run标签
for (int pos = 0; pos < newParagraph.getRuns().size(); pos++) {
newParagraph.removeRun(pos);
}
for (XWPFRun s : templateParagraph.getRuns()) {
XWPFRun targetrun = newParagraph.createRun();
CopyRun(targetrun, s);
}
}
/**
* 复制文本节点run
*
* @param newRun 新创建的的文本节点
* @param templateRun 模板文本节点
*/
private void CopyRun(XWPFRun newRun, XWPFRun templateRun) {
newRun.getCTR().setRPr(templateRun.getCTR().getRPr());
// 设置文本
newRun.setText(templateRun.text());
}
/**
* 根据参数parametersMap对表格的一行进行标签的替换
*
* @param tableRow 表格行
* @param paramsMap 参数map
*/
public void replaceTableRow(XWPFTableRow tableRow, Map<String, Object> paramsMap) {
List<XWPFTableCell> tableCells = tableRow.getTableCells();
for (XWPFTableCell xWPFTableCell : tableCells) {
List<XWPFParagraph> paragraphs = xWPFTableCell.getParagraphs();
for (XWPFParagraph xwpfParagraph : paragraphs) {
replaceParagraph(xwpfParagraph, paramsMap);
}
}
}
/**
* 根据map替换表格中的{key}标签
*
* @param xwpfTable
* @param paramsMap
*/
public void replaceTable(XWPFTable xwpfTable, Map<String, Object> paramsMap) {
List<XWPFTableRow> rows = xwpfTable.getRows();
for (XWPFTableRow xWPFTableRow : rows) {
List<XWPFTableCell> tableCells = xWPFTableRow.getTableCells();
for (XWPFTableCell xWPFTableCell : tableCells) {
List<XWPFParagraph> paragraphs2 = xWPFTableCell.getParagraphs();
for (XWPFParagraph xWPFParagraph : paragraphs2) {
replaceParagraph(xWPFParagraph, paramsMap);
}
}
}
}
private String getValueByKey(String key, Map<String, Object> map) {
String returnValue = "";
if (key != null) {
try {
returnValue = map.get(key) != null ? map.get(key).toString() : "";
} catch (Exception e) {
// TODO: handle
// exception
logger.info("key:" + key + "***" + e);
returnValue = "";
}
}
return returnValue;
}
public static void main(String[] args) throws IOException {
Map<String, Object> paramsMap = new HashMap<>();
paramsMap.put("dateTime", "2022-8-20");
paramsMap.put("no", "2022001");
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("paramsMap", paramsMap);
WordTemplateUtil wordTemplateUtil = new WordTemplateUtil(new FileInputStream("/Users/yanshao/Desktop/模版.doc"));
// 替换标签
wordTemplateUtil.replaceDocument(dataMap);
// 替换文本列表
// Map<String, List<String>> testListMap = buildTextListMap(orderAddrList);
// wordTemplateUtil.replaceParagraphList(testListMap);
// 转换为输入流返回
wordTemplateUtil.getDocument().write(new FileOutputStream("/Users/yanshao/Desktop/结果文件.doc"));
}
}
模版:

结果:
