在工作中我接触到的word类型主要有三种类型,分别是段落、表格、表格中的段落,这三种有可能同时出现,下面的内容会分别给出这几种类型的解决方案,以及页眉、页脚的填充。
表格中的段落就是指下图中这种一个单元格中有行并且有多个需要填充的地方。
poi填充word原理其实是识别word模板中的值,然后进行替换,一般会以${xxx}作为标记
依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.0</version>
</dependency>
1.段落
Map<String, String> map = new HashMap<>();
map.put("aaa","122");//map的key为模板中替换的对象,value为替换的值
InputStream is = this.getClass().getResourceAsStream("/demo.docx");
XWPFDocument document = new XWPFDocument(is);
Set<String> set = map.keySet();
Iterator<XWPFParagraph> itPara = document.getParagraphsIterator();//获取word段落
while (itPara.hasNext()) {
XWPFParagraph paragraph = itPara.next();//获取段落
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
String key = iterator.next();//获取key
List<XWPFRun> run = paragraph.getRuns();//获取行
for (int i = 0; i < run.size(); i++) {
//如果key等于word中的值,就替换
if (run.get(i).getText(run.get(i).getTextPosition()) != null &&
run.get(i).getText(run.get(i).getTextPosition()).equals(key)) {
run.get(i).setText(map.get(key), 0);//0指从第一个字符开始替换
}
}
}
}
//导出文件存在本地
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
document.write((OutputStream) byteArrayOutputStream);
String filePath = "D://uploads/demo/";//存储目的地
String fileName = "demo";//文件名称
File file = new File(filePath + fileName + ".docx");
//如果不存在文件夹则创建
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
FileOutputStream outputStream = new FileOutputStream(filePath + fileName + ".docx");
outputStream.write(byteArrayOutputStream.toByteArray());
outputStream.flush();
outputStream.close();
2.表格
Map<String, String> map = new HashMap<>();
map.put("aaa","122");//map的key为模板中替换的对象,value为替换的值
InputStream is = this.getClass().getResourceAsStream("/demo.docx");
WPFDocument document = new XWPFDocument(is);
List<XWPFTable> tables = document.getTables();//获取表格
Set<String> set = map.keySet();
for (XWPFTable table : tables) {
List<XWPFTableRow> rows = table.getRows();//获取行
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();//获取单元格
for (XWPFTableCell cell : cells) {
for (String s : set) {
//判断行是否包含map中的key,若包含,则用value替换行中key的内容
if (cell.getText().contains(s)) {
//用来存储替换后的行数据
String replace = "";
replace = cell.getText().replace(s, map.get(s));
//删除原来的行
cell.removeParagraph(0);
//新增一行
XWPFParagraph para = cell.addParagraph();
para.setSpacingBetween(1);
//填充数据
cell.setText(replace);
}
}
}
}
}
//导出文件存在本地
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
document.write((OutputStream) byteArrayOutputStream);
String filePath = "D://uploads/demo/";//存储目的地
String fileName = "demo";//文件名称
File file = new File(filePath + fileName + ".docx");
//如果不存在文件夹则创建
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
FileOutputStream outputStream = new FileOutputStream(filePath + fileName + ".docx");
outputStream.write(byteArrayOutputStream.toByteArray());
outputStream.flush();
outputStream.close();
3.表格中的段落(可通用普通表格),精髓在这,其他与上同
for (XWPFTable table : tables) {
List<XWPFTableRow> rows = table.getRows();//获取行
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();//获取单元格
for (XWPFTableCell cell : cells) {
//用以判断是否有值更改
int a = 0;
//记录单元格原值
String replace = cell.getText();
for (String s : set) {
//判断单元格的值是否包含key
if (cell.getText().contains(s)) {
a = 1;
//替换key
replace = replace.replace(s, map.get(s));
}
}
//有替换值
if (a == 1) {
//获取当前单元格行数
int size = cell.getParagraphs().size();
for (int i = 0; i < size; i++) {
//删除原数据
cell.removeParagraph(0);
}
//这个字符截取需要提前在word模板中在需要回车的地方加上'|',不然的话是不会换行的
String[] jdcl = replace.split("\\|");
for (int i = 0; i < jdcl.length; i++) {
XWPFParagraph xwpfParagraph = cell.addParagraph();//新建段落
XWPFRun run = xwpfParagraph.createRun();//新建行
run.setText(jdcl[i]);赋值
}
}
}
}
}
}
4.页眉、页脚
页眉与页脚的处理方式其实与上述内容都是类似的,只是获取word不同位置的内容而已
页眉
Map<String, String> map = new HashMap<>();
map.put("${a}","123");
InputStream is = this.getClass().getResourceAsStream("/demo.docx");
XWPFDocument document = new XWPFDocument(is);
List<XWPFHeader> headerList = document.getHeaderList();
for (XWPFHeader xwpfHeader : headerList) {
List<XWPFParagraph> paragraphs = xwpfHeader.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
List<XWPFRun> runs = paragraph.getRuns();
for (int i = 0; i < runs.size(); i++) {
for (String s : set) {
if (runs.get(i).getText(runs.get(i).getTextPosition()) != null &&
runs.get(i).getText(runs.get(i).getTextPosition()).contains(s)) {
String replace = runs.get(i).getText(runs.get(i).getTextPosition()).replace(s, map.get(s));
runs.get(i).setText(replace, 0);
}
}
}
}
}
页脚
Map<String, String> map = new HashMap<>();
map.put("${a}","123");
InputStream is = this.getClass().getResourceAsStream("/demo.docx");
XWPFDocument document = new XWPFDocument(is);
List<XWPFFooter> footerList = document.getFooterList();
for (XWPFFooter xwpfFooter : footerList) {
List<XWPFParagraph> paragraphs = xwpfFooter.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
List<XWPFRun> runs = paragraph.getRuns();
for (int i = 0; i < runs.size(); i++) {
for (String s : set) {
if (runs.get(i).getText(runs.get(i).getTextPosition()) != null &&
runs.get(i).getText(runs.get(i).getTextPosition()).contains(s)) {
String replace = runs.get(i).getText(runs.get(i).getTextPosition()).replace(s, map.get(s));
runs.get(i).setText(replace, 0);
}
}
}
}
}