java Poi 生成word文档 生成的文档后返回 InputStream 流
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
/**
* @author: chenjx
* @create: 2022/9/21 09:56
**/
@Component
public class TestCreateFile {
/**
* 文件路径
*/
private static final String FOP = "/ftl/cc.docx";
/**
* $
*/
private static final String CHARACTER_$ = "$";
/**
* 根据docx模版生成docx文件
*
* @param templateName 模版路径名称
* @param insertTextMap ${} 字符替换
* @param map 表格数据需循环新增
* @throws IOException 异常
*/
public InputStream generateWord(String templateName, Map<String, Object> insertTextMap, Map<Integer, List<String[]>> map) throws IOException {
ClassPathResource classPathResource = new ClassPathResource(templateName);
InputStream inputStream = null;
//获取docx解析对象
XWPFDocument xwpfDocument = null;
try {
inputStream = classPathResource.getInputStream();
//获取docx解析对象
xwpfDocument = new XWPFDocument(inputStream);
// 处理所有文段数据,除了表格
handleParagraphs(xwpfDocument, insertTextMap);
// 处理表格数据
handleTable(xwpfDocument, insertTextMap, map);
//二进制OutputStream
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//文档写入流
xwpfDocument.write(baos);
//OutputStream写入InputStream二进制流
return new ByteArrayInputStream(baos.toByteArray());
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (inputStream != null) {
inputStream.close();
}
if (xwpfDocument != null) {
xwpfDocument.close();
}
}
}
/**
* 处理需要替换的数据和 需要表格新增的数据
*
* @param xwpfDocument docx
* @param insertTextMap ${} 数据
* @param map 表格数据
*/
public static void handleTable(XWPFDocument xwpfDocument, Map<String, Object> insertTextMap, Map<Integer, List<String[]>> map) {
List<XWPFTable> tables = xwpfDocument.getTables();
int tableIndex = 0;
for (XWPFTable table : tables) {
//表格坐标
tableIndex++;
List<XWPFTableRow> rows = table.getRows();
if (rows.size() > 1) {
if (isReplacement(table.getText())) {
// 替换数据
rows.stream().map(XWPFTableRow::getTableCells).forEach(tableCells -> tableCells.stream().filter(tableCell -> isReplacement(tableCell.getText())).forEach(tableCell -> {
List<XWPFParagraph> paragraphs = tableCell.getParagraphs();
//替换数据
paragraphs.stream().map(XWPFParagraph::getRuns).flatMap(Collection::stream).forEach(run -> run.setText(matchesValue(tableCell.getText(), insertTextMap), 0));
}));
} else {
//处理新增表格数据
List<String[]> strings = map.get(tableIndex);
// 插入数据
IntStream.range(1, strings.size()).forEach(i -> 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(strings.get(i - 1)[j]);
}
}
}
}
}
}
/**
* 替换带有 ${}的数据
*
* @param wordValue 表格文本
* @param map 数据
* @return 数据
*/
public static String matchesValue(String wordValue, Map<String, Object> map) {
for (String s : map.keySet()) {
String s1 = "${" + s + "}";
if (s1.equals(wordValue)) {
wordValue = String.valueOf(map.get(s));
}
}
return wordValue;
}
/**
* 判断是否有包含需替换的数据
*
* @param text 文本
* @return boolean
*/
public static boolean isReplacement(String text) {
boolean check = false;
if (text.contains(CHARACTER_$)) {
check = true;
}
return check;
}
/**
* 处理文段数据
*
* @param xwpfDocument docx
* @param insertTextMap ${}数据
*/
public static void handleParagraphs(XWPFDocument xwpfDocument, Map<String, Object> insertTextMap) {
xwpfDocument.getParagraphs().forEach(paragraph -> {
String text = paragraph.getText();
if (isReplacement(text)) {
for (XWPFRun run : paragraph.getRuns()) {
// 判断带有${}的run
run.setText(matchesValue(run.text(), insertTextMap), 0);
}
}
});
}
}
// 请求eg
public ObjectResult<AddFileInfoVo> testFile() {
// 替换文本数据构建
HashMap<String, Object> insertTextMap = new HashMap<>(16);
insertTextMap.put("orgName", "单位啊啊啊--");
insertTextMap.put("name", "你猜猜");
insertTextMap.put("deptName", "我不听");
// 插入数据构建
ArrayList<String[]> addList = new ArrayList<>();
addList.add(new String[]{"【插入11】", "【插入12】"});
addList.add(new String[]{"【插入21】", "【插入22】"});
// 插入数据构建
ArrayList<String[]> addList1 = new ArrayList<>();
addList1.add(new String[]{"【插入11】", "【插入12】"});
addList1.add(new String[]{"【插入21】", "【插入22】"});
addList1.add(new String[]{"【插入31】", "【插入32】"});
//map的key为word模版中的第几个表格就为几,比如要给第二个表格加数据,则key为2
Map<Integer, List<String[]>> map = new HashMap<>();
map.put(2, addList);
map.put(3, addList1);
InputStream inputStream = null;
ObjectResult<AddFileInfoVo> addFileInfoVoObjectResul;
try {
inputStream = testCreateFile.generateWord("/ftl/cc.docx", insertTextMap, map);
addFileInfoVoObjectResul = commonServiceClient.addFileInfo(0, inputStream, "测试xxw生成word.docx");
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
return addFileInfoVoObjectResul;
}
举例:
我的模版:
自动生成的数据:
也可给流输出保存本地
//filePath为保存到本地的路径 uuid 为随机生成的文件名
InputStream inputStream = classPathResource.getInputStream();
String fileLocal = String.format("%s%s.docx", filePath, UUID.randomUUID());
// 设置模板输入和结果输出
fileOutputStream = new FileOutputStream(fileLocal);
//获取docx解析对象
XWPFDocument xwpfDocument = new XWPFDocument(inputStream);
// 处理所有文段数据,除了表格
handleParagraphs(xwpfDocument, insertTextMap);
// 处理表格数据
handleTable(xwpfDocument, insertTextMap, map);
// 写出数据
xwpfDocument.write(fileOutputStream);
jar包:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>