Apache POI 常用操作指南

4170 admin
世界杯开球

Apache POI 常用操作指南

1. Apache POI 介绍

介绍:Apache POI 是一个功能全面的库,用于操作 Microsoft Office 文件(包括 Excel、Word、PowerPoint 等)。

特点:

支持 Excel 97-2003(.xls)和 Excel 2007+(.xlsx)。提供低层次和高层次的 API。支持格式化单元格、公式计算、数据验证等复杂操作。

适用场景:需要灵活操作 Excel 表格,且对性能要求不苛刻。

与其他操作 Excel 的库对比,比如EasyExcel

介绍:由阿里巴巴开源,专注于高效处理 Excel 文件。

特点:

专为大规模数据读写设计,性能优于 Apache POI。使用注解和 Java Bean,简化 Excel 读写操作。支持大文件的分批处理,降低内存占用。

适用场景:需要快速读写大规模 Excel 数据。

2.依赖配置&快速开始

Maven pom.xml

org.apache.poi

poi

5.2.2

org.apache.poi

poi-ooxml

5.2.2

commons-io

commons-io

2.18.0

org.apache.logging.log4j

log4j-core

2.20.0

org.apache.logging.log4j

log4j-api

2.20.0

测试依赖

public class POITest {

public static void main(String[] args) {

XSSFWorkbook workbook = new XSSFWorkbook();

System.out.println("POI 环境配置成功!");

}

}

3.Excel基础操作

3.1读取Excel文件

以下是一个简单的读取 .xlsx 文件的例子:

public class ReadExcel {

public static void main(String[] args) {

String filePath = "D:\\workspace\\javaWorkspace\\SpringBoot-demo\\poi-demo\\poi_test.xlsx";

try (FileInputStream fis = new FileInputStream(filePath);

Workbook workbook = new XSSFWorkbook(fis)) {

// 获取第一个工作表

Sheet sheet = workbook.getSheetAt(0);

// 遍历行

for (Row row : sheet) {

// 遍历单元格

for (Cell cell : row) {

switch (cell.getCellType()) {

case STRING:

System.out.print(cell.getStringCellValue() + "\t");

break;

case NUMERIC:

System.out.print(cell.getNumericCellValue() + "\t");

break;

case BOOLEAN:

System.out.print(cell.getBooleanCellValue() + "\t");

break;

default:

System.out.print("未知类型\t");

}

}

System.out.println();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

输入文件:确保项目根目录中有一个名为 poi_test.xlsx 的 Excel 文件。

输出结果:逐行打印 Excel 文件内容。

3.2写入 Excel 文件

我们将创建一个新的 .xlsx 文件,并向其中写入数据。

import org.apache.poi.ss.usermodel.*;

import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileOutputStream;

import java.io.IOException;

public class WriteExcel {

public static void main(String[] args) {

// 创建一个工作簿

Workbook workbook = new XSSFWorkbook();

// 创建一个工作表

Sheet sheet = workbook.createSheet("示例工作表");

// 创建表头

Row headerRow = sheet.createRow(0);

String[] columns = {"姓名", "年龄", "性别", "职业"};

for (int i = 0; i < columns.length; i++) {

Cell cell = headerRow.createCell(i);

cell.setCellValue(columns[i]);

}

// 填充数据

Object[][] data = {

{"张三", 25, "男", "工程师"},

{"李四", 30, "女", "设计师"},

{"王五", 28, "男", "产品经理"},

};

for (int i = 0; i < data.length; i++) {

Row row = sheet.createRow(i + 1); // 从第2行开始写数据

for (int j = 0; j < data[i].length; j++) {

Cell cell = row.createCell(j);

if (data[i][j] instanceof String) {

cell.setCellValue((String) data[i][j]);

} else if (data[i][j] instanceof Integer) {

cell.setCellValue((Integer) data[i][j]);

}

}

}

// 自动调整列宽

for (int i = 0; i < columns.length; i++) {

sheet.autoSizeColumn(i);

}

// 写入到文件

try (FileOutputStream fileOut = new FileOutputStream("example.xlsx")) {

workbook.write(fileOut);

System.out.println("Excel 文件已成功创建!");

} catch (IOException e) {

e.printStackTrace();

}

// 关闭工作簿

try {

workbook.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

代码说明

创建工作簿和工作表:

使用 XSSFWorkbook 创建一个 .xlsx 文件。使用 createSheet 方法创建一个工作表。 写入数据:

表头部分:通过 createRow 和 createCell 创建行和单元格。数据部分:通过嵌套循环写入多行多列的数据。 自动调整列宽:

sheet.autoSizeColumn(i) 方法可以根据内容动态调整列宽。 保存文件:

使用 FileOutputStream 将工作簿写入文件。 关闭资源:

POI 提供的工作簿资源需要在使用完后关闭,以避免内存泄漏

3.3格式化单元格&合并单元格

Apache POI 提供了强大的样式设置功能,通过 CellStyle 和 Font 类可以轻松设置单元格的格式。

示例代码:格式化 Excel 单元格

public class ExcelCellFormatting {

public static void main(String[] args) {

Workbook workbook = new XSSFWorkbook();

Sheet sheet = workbook.createSheet("格式化示例");

// 创建标题行

Row headerRow = sheet.createRow(0);

CellStyle headerStyle = workbook.createCellStyle();

Font headerFont = workbook.createFont();

// 设置标题字体样式

headerFont.setFontName("Arial");

headerFont.setFontHeightInPoints((short) 14); // 字体大小

headerFont.setBold(true); // 加粗

headerStyle.setFont(headerFont);

headerStyle.setAlignment(HorizontalAlignment.CENTER); // 水平居中

headerStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中

headerStyle.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex()); // 背景色

headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

// 设置边框

headerStyle.setBorderBottom(BorderStyle.THICK);

headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());

// 填充标题数据

String[] headers = {"姓名", "年龄", "性别", "职业"};

for (int i = 0; i < headers.length; i++) {

Cell cell = headerRow.createCell(i);

cell.setCellValue(headers[i]);

cell.setCellStyle(headerStyle);

}

// 添加数据行

Object[][] data = {

{"张三", 25, "男", "工程师"},

{"李四", 30, "女", "设计师"},

{"王五", 28, "男", "产品经理"},

};

CellStyle dataStyle = workbook.createCellStyle();

Font dataFont = workbook.createFont();

dataFont.setFontName("Calibri");

dataFont.setFontHeightInPoints((short) 12);

dataStyle.setFont(dataFont);

dataStyle.setAlignment(HorizontalAlignment.LEFT);

for (int i = 0; i < data.length; i++) {

Row row = sheet.createRow(i + 1);

for (int j = 0; j < data[i].length; j++) {

Cell cell = row.createCell(j);

if (data[i][j] instanceof String) {

cell.setCellValue((String) data[i][j]);

} else if (data[i][j] instanceof Integer) {

cell.setCellValue((Integer) data[i][j]);

}

cell.setCellStyle(dataStyle);

}

}

// 自动调整列宽

for (int i = 0; i < headers.length; i++) {

sheet.autoSizeColumn(i);

}

// 输出到文件

try (FileOutputStream fileOut = new FileOutputStream("formatted_example.xlsx")) {

workbook.write(fileOut);

System.out.println("Excel 文件已成功创建!");

} catch (IOException e) {

e.printStackTrace();

}

// 关闭工作簿

try {

workbook.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

import org.apache.poi.ss.usermodel.*;

import org.apache.poi.xssf.usermodel.*;

import org.apache.poi.ss.util.CellRangeAddress;

import java.io.FileOutputStream;

public class MergeCellsExample {

public static void main(String[] args) {

// 1. 创建工作簿和工作表

XSSFWorkbook workbook = new XSSFWorkbook();

XSSFSheet sheet = workbook.createSheet("合并单元格示例");

// 2. 创建合并的单元格区域(第1行,第1列 到 第1行,第3列)

CellRangeAddress mergedRegion = new CellRangeAddress(0, 0, 0, 2); // 参数: 起始行, 结束行, 起始列, 结束列

sheet.addMergedRegion(mergedRegion);

// 3. 在合并的单元格中写入内容

Row row = sheet.createRow(0);

Cell cell = row.createCell(0);

cell.setCellValue("合并的单元格内容");

// 4. 设置单元格样式(可选)

CellStyle style = workbook.createCellStyle();

style.setAlignment(HorizontalAlignment.CENTER); // 水平居中

style.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中

cell.setCellStyle(style);

// 5. 输出到文件

try (FileOutputStream fileOut = new FileOutputStream("merged-cells-example.xlsx")) {

workbook.write(fileOut);

System.out.println("Excel 文件创建成功!");

} catch (Exception e) {

e.printStackTrace();

}

}

}

3.4写入多个工作表

// 第一个工作表:人员信息

//writeSheetData 同写入excel代码操作,自己实现

Sheet sheet1 = workbook.createSheet("人员信息");

writeSheetData(sheet1, new String[][]{

{"姓名", "年龄", "性别", "职业"},

{"张三", "25", "男", "工程师"},

{"李四", "30", "女", "设计师"},

{"王五", "28", "男", "产品经理"}

});

// 第二个工作表:工资信息

Sheet sheet2 = workbook.createSheet("工资信息");

writeSheetData(sheet2, new String[][]{

{"姓名", "基本工资", "奖金", "总工资"},

{"张三", "8000", "2000", "10000"},

{"李四", "9000", "1500", "10500"},

{"王五", "7500", "1800", "9300"}

});

// 第三个工作表:考勤信息

Sheet sheet3 = workbook.createSheet("考勤信息");

writeSheetData(sheet3, new String[][]{

{"姓名", "出勤天数", "请假天数", "缺勤天数"},

{"张三", "22", "2", "1"},

{"李四", "23", "1", "0"},

{"王五", "21", "3", "2"}

});

3.5 Apache POI 的数据验证功能

3.5.1 静态数据下拉

实现步骤

创建一个工作表(Sheet)。定义下拉列表的数据来源(可以是静态数组或单元格区域)。使用 DataValidationHelper 和 DataValidationConstraint 创建数据验证规则。将数据验证规则应用到目标单元格区域。

示例代码:静态数据设置下拉列表

public class ExcelDropdown {

public static void main(String[] args) {

Workbook workbook = new XSSFWorkbook();

Sheet sheet = workbook.createSheet("下拉列表示例");

Row headRow = sheet.createRow(0);

// 填充标题数据

String[] headers = {"姓名", "年龄", "性别", "职业"};

for (int i = 0; i < headers.length; i++) {

Cell cell = headRow.createCell(i);

cell.setCellValue(headers[i]);

}

// 1. 定义下拉列表的选项

String[] options = {"男", "女", "未知"};

// 2. 设置下拉列表的作用范围(行和列)

CellRangeAddressList addressList = new CellRangeAddressList(1, 10, 2, 2);// 第2列(C列),从第2行到第11行

// 3. 创建数据验证对象

DataValidationHelper validationHelper = sheet.getDataValidationHelper();

DataValidationConstraint constraint = validationHelper.createExplicitListConstraint(options);

DataValidation validation = validationHelper.createValidation(constraint, addressList);

// 4. 设置数据验证规则的行为

//setShowErrorBox(true):输入不在下拉选项内的数据时显示错误框。

//setSuppressDropDownArrow(true):在单元格右侧显示下拉箭头。

validation.setShowErrorBox(true);

validation.setSuppressDropDownArrow(true);

// 5. 将验证规则添加到工作表

sheet.addValidationData(validation);

// 保存 Excel 文件

try (FileOutputStream fileOut = new FileOutputStream("excel_dropdown_example.xlsx")) {

workbook.write(fileOut);

System.out.println("Excel 文件生成成功,已设置下拉列表!");

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

workbook.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

3.5.2 动态数据下拉

有时候,下拉选项需要来源于 Excel 的某个区域,而不是静态数组。

示例代码:动态单元格区域作为下拉列表数据

java复制代码import org.apache.poi.ss.usermodel.*;

import org.apache.poi.ss.util.CellRangeAddressList;

import org.apache.poi.ss.util.CellReference;

import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileOutputStream;

import java.io.IOException;

public class ExcelDynamicDropdown {

public static void main(String[] args) {

Workbook workbook = new XSSFWorkbook();

Sheet sheet = workbook.createSheet("动态下拉示例");

// 1. 在 A 列(第 1 列)写入下拉选项数据

sheet.createRow(0).createCell(0).setCellValue("男");

sheet.createRow(1).createCell(0).setCellValue("女");

sheet.createRow(2).createCell(0).setCellValue("未知");

// 2. 设置下拉列表的作用范围

CellRangeAddressList addressList = new CellRangeAddressList(1, 10, 2, 2); // C列

// 3. 数据验证:引用单元格区域 A1:A3 作为下拉选项

DataValidationHelper validationHelper = sheet.getDataValidationHelper();

String formula = "Sheet0!$A$1:$A$3"; // 数据范围引用

DataValidationConstraint constraint = validationHelper.createFormulaListConstraint(formula);

DataValidation validation = validationHelper.createValidation(constraint, addressList);

// 4. 添加验证规则

sheet.addValidationData(validation);

// 保存文件

try (FileOutputStream fileOut = new FileOutputStream("dynamic_dropdown.xlsx")) {

workbook.write(fileOut);

System.out.println("Excel 文件已生成,动态下拉列表设置完成!");

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

workbook.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

3.5.2 级联数据下拉

实现思路

准备静态数据:定义第一个下拉列表的选项(如:类别),并准备对应的第二级选项(子项)。动态关联:使用 Excel 的 Named Range(名称管理器)将第二级选项与第一级选项动态关联。INDIRECT 函数:通过 Excel 的 INDIRECT 函数来实现级联效果,第二个下拉列表引用动态名称范围。

示例代码:级联下拉列表实现

java复制代码import org.apache.poi.ss.usermodel.*;

import org.apache.poi.ss.util.CellRangeAddressList;

import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileOutputStream;

import java.io.IOException;

public class CascadingDropdown {

public static void main(String[] args) {

Workbook workbook = new XSSFWorkbook();

Sheet sheet = workbook.createSheet("级联下拉示例");

// 1. 准备数据

// 第一列:城市

Row row0 = sheet.createRow(0);

row0.createCell(0).setCellValue("城市");

row0.createCell(1).setCellValue("北京");

row0.createCell(2).setCellValue("上海");

row0.createCell(3).setCellValue("广州");

// 北京的区县

sheet.createRow(1).createCell(1).setCellValue("东城");

sheet.createRow(2).createCell(1).setCellValue("西城");

sheet.createRow(3).createCell(1).setCellValue("朝阳");

// 上海的区县

sheet.getRow(1).createCell(2).setCellValue("黄浦");

sheet.getRow(2).createCell(2).setCellValue("徐汇");

sheet.getRow(3).createCell(2).setCellValue("静安");

// 广州的区县

sheet.getRow(1).createCell(3).setCellValue("天河");

sheet.getRow(2).createCell(3).setCellValue("越秀");

sheet.getRow(3).createCell(3).setCellValue("白云");

// 2. 设置第一级下拉列表(城市)

DataValidationHelper validationHelper = sheet.getDataValidationHelper();

CellRangeAddressList cityRange = new CellRangeAddressList(5, 5, 0, 0); // 第6行,第1列

DataValidationConstraint cityConstraint = validationHelper.createExplicitListConstraint(

new String[]{"北京", "上海", "广州"});

DataValidation cityValidation = validationHelper.createValidation(cityConstraint, cityRange);

sheet.addValidationData(cityValidation);

// 3. 设置第二级下拉列表(区县),使用 INDIRECT 动态引用名称管理器

for (int i = 5; i <= 5; i++) { // 第6行

CellRangeAddressList districtRange = new CellRangeAddressList(i, i, 1, 1); // 第2列

String formula = "INDIRECT($A$" + (i + 1) + ")";

DataValidationConstraint districtConstraint = validationHelper.createFormulaListConstraint(formula);

DataValidation districtValidation = validationHelper.createValidation(districtConstraint, districtRange);

sheet.addValidationData(districtValidation);

}

// 4. 命名单元格区域(名称管理器设置)

Name beijing = workbook.createName();

beijing.setNameName("北京");

beijing.setRefersToFormula("Sheet0!$B$2:$B$4");

Name shanghai = workbook.createName();

shanghai.setNameName("上海");

shanghai.setRefersToFormula("Sheet0!$C$2:$C$4");

Name guangzhou = workbook.createName();

guangzhou.setNameName("广州");

guangzhou.setRefersToFormula("Sheet0!$D$2:$D$4");

// 5. 保存文件

try (FileOutputStream fileOut = new FileOutputStream("cascading_dropdown.xlsx")) {

workbook.write(fileOut);

System.out.println("Excel 级联下拉列表已生成!");

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

workbook.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

4.Word基础操作

4.1 Apache POI 操作 Word 概述

Apache POI 提供了 XWPF 系列的类来处理 .docx 格式的 Word 文档,包括:

XWPFDocument:表示整个 Word 文档。XWPFParagraph:表示段落。XWPFRun:表示段落中的文本片段,可以设置字体、大小、加粗、颜色等。XWPFTable:表示表格。XWPFTableRow / XWPFTableCell:表示表格中的行和单元格。

4.2快速开始

代码示例

java复制代码import org.apache.poi.xwpf.usermodel.*;

import java.io.FileOutputStream;

public class WordExample {

public static void main(String[] args) {

// 1. 创建一个空白的 Word 文档

XWPFDocument document = new XWPFDocument();

try {

// 2. 添加一个段落

XWPFParagraph paragraph = document.createParagraph();

paragraph.setAlignment(ParagraphAlignment.CENTER); // 段落居中对齐

// 3. 在段落中添加文本内容

XWPFRun run = paragraph.createRun();

run.setText("Hello, Apache POI for Word!");

run.setBold(true); // 加粗

run.setFontFamily("微软雅黑"); // 字体

run.setFontSize(14); // 字号

run.setColor("0000FF"); // 字体颜色(蓝色)

// 4. 将 Word 文档保存到文件中

FileOutputStream out = new FileOutputStream("example.docx");

document.write(out);

out.close();

document.close();

System.out.println("Word 文档创建成功!");

} catch (Exception e) {

e.printStackTrace();

}

}

}

代码解析

创建文档: XWPFDocument document = new XWPFDocument();

这是 Word 操作的入口,创建一个空白的 .docx 文档。 添加段落:

通过 document.createParagraph() 方法创建一个段落。 向段落中添加文本:

使用 XWPFRun run = paragraph.createRun(); 添加文本片段。可设置样式,如:字体、大小、加粗、颜色等。 保存文档:

通过 FileOutputStream 将文档写入到文件中。

4.3word插入表格

示例代码:创建表格并写入数据

java复制代码import org.apache.poi.xwpf.usermodel.*;

import java.io.FileOutputStream;

public class WordTableExample {

public static void main(String[] args) {

// 1. 创建一个 Word 文档

XWPFDocument document = new XWPFDocument();

try {

// 2. 创建一个表格(2 行 3 列)

XWPFTable table = document.createTable(2, 3);

// 3. 设置表格中的数据

// 第一行:表头

table.getRow(0).getCell(0).setText("姓名");

table.getRow(0).getCell(1).setText("年龄");

table.getRow(0).getCell(2).setText("职业");

// 第二行:数据

table.getRow(1).getCell(0).setText("张三");

table.getRow(1).getCell(1).setText("25");

table.getRow(1).getCell(2).setText("工程师");

// 4. 添加样式(可选)

XWPFTableRow row1 = table.getRow(0);

for (XWPFTableCell cell : row1.getTableCells()) {

XWPFParagraph paragraph = cell.getParagraphs().get(0);

XWPFRun run = paragraph.createRun();

run.setBold(true); // 设置表头加粗

run.setFontFamily("微软雅黑");

run.setFontSize(12);

}

// 5. 将 Word 文档写入文件

FileOutputStream out = new FileOutputStream("table-example.docx");

document.write(out);

out.close();

document.close();

System.out.println("Word 表格文档创建成功!");

} catch (Exception e) {

e.printStackTrace();

}

}

}

4.4插入图片

通过 Apache POI,可以方便地将图片插入到 Word 文档中。 图片格式支持:PNG、JPG、GIF、BMP 等。

示例代码:向 Word 文档插入图片

java复制代码import org.apache.poi.xwpf.usermodel.*;

import java.io.FileInputStream;

import java.io.FileOutputStream;

public class WordImageExample {

public static void main(String[] args) {

// 1. 创建一个 Word 文档

XWPFDocument document = new XWPFDocument();

try {

// 2. 添加一个段落

XWPFParagraph paragraph = document.createParagraph();

XWPFRun run = paragraph.createRun();

// 3. 插入图片

String imagePath = "example.png"; // 图片路径(替换成你的图片路径)

FileInputStream is = new FileInputStream(imagePath);

// 添加图片到文档

// 计算图片尺寸(单位:EMU)

int width = 200 * 9525; // 200px 宽

int height = 100 * 9525; // 100px 高

// 1 英寸 = 914400 EMU

// 1 厘米 = 360000 EMU

// 1 像素 ≈ 9525 EMU

// 添加图片到文档

run.addPicture(is, Document.PICTURE_TYPE_PNG, imagePath, width, height);

// 参数说明:

// is: 图片输入流

// PICTURE_TYPE_PNG: 图片类型(其他如 Document.PICTURE_TYPE_JPEG)

// imagePath: 图片路径

// 宽: 200px,高: 100px

is.close();

// 4. 保存 Word 文档

FileOutputStream out = new FileOutputStream("image-example.docx");

document.write(out);

out.close();

document.close();

System.out.println("Word 文档插入图片成功!");

} catch (Exception e) {

e.printStackTrace();

}

}

}

4.5 word内容读取

在 Apache POI 中,Word 文档内容的读取分为两种情况:

.docx 文件(基于 XML 格式,使用 XWPFDocument)。.doc 文件(旧格式,使用 HWPFDocument)。

我们将先学习如何读取 .docx 文件。

示例代码:读取 .docx 文档的文本内容

import java.io.FileInputStream;

public class ReadWordExample {

public static void main(String[] args) {

try {

// 1. 读取 .docx 文件

FileInputStream fis = new FileInputStream("example.docx");

XWPFDocument document = new XWPFDocument(fis);

// 2. 遍历段落,读取文本内容

System.out.println("读取 Word 文档中的段落内容:");

for (XWPFParagraph paragraph : document.getParagraphs()) {

System.out.println(paragraph.getText());

}

// 3. 遍历表格,读取表格中的内容

System.out.println("\n读取 Word 文档中的表格内容:");

for (XWPFTable table : document.getTables()) {

for (XWPFTableRow row : table.getRows()) {

for (XWPFTableCell cell : row.getTableCells()) {

System.out.print(cell.getText() + "\t");

}

System.out.println();

}

}

// 4. 关闭流

document.close();

fis.close();

} catch (Exception e) {

e.printStackTrace();

}

}

}

4.6 word固定模板占位符替换(扩展)

占位符替换的实现原理

创建 Word 模板 在 Word 文档中使用占位符,例如:${name}、${date}、${title} 等。加载 Word 文档 使用 XWPFDocument 读取模板文件。替换占位符 遍历文档中的所有段落和表格单元格,将占位符替换为实际值。保存新文档 将替换后的 Word 文档保存到新的文件中。

docx模板内容

尊敬的 ${name},

感谢您于 ${date} 前来参加 ${title} 活动。

祝您一切顺利!

代码示例:替换占位符

public class ReplacePlaceholderExample {

public static void main(String[] args) {

String filePath = "D:\\workspace\\javaWorkspace\\SpringBoot-demo\\poi-demo\\template.docx";

try {

// 1. 加载 Word 模板

FileInputStream fis = new FileInputStream(filePath);

XWPFDocument document = new XWPFDocument(fis);

// 2. 定义替换的占位符和实际值

Map placeholders = new HashMap<>();

placeholders.put("${name}", "张三");

placeholders.put("${date}", "2024-06-20");

placeholders.put("${title}", "技术分享会");

// 3. 遍历所有段落,替换占位符

for (XWPFParagraph paragraph : document.getParagraphs()) {

replacePlaceholdersInParagraph(paragraph, placeholders);

}

// 4. 遍历表格,替换占位符(如果有表格)

for (XWPFTable table : document.getTables()) {

for (XWPFTableRow row : table.getRows()) {

for (XWPFTableCell cell : row.getTableCells()) {

for (XWPFParagraph paragraph : cell.getParagraphs()) {

replacePlaceholdersInParagraph(paragraph, placeholders);

}

}

}

}

// 5. 保存新文档

String newFilePath = "D:\\workspace\\javaWorkspace\\SpringBoot-demo\\poi-demo\\template_output.docx";

FileOutputStream fos = new FileOutputStream(newFilePath);

document.write(fos);

// 6. 关闭流

fos.close();

document.close();

fis.close();

System.out.println("占位符替换完成,文档已保存为 output.docx");

} catch (IOException e) {

throw new RuntimeException(e);

}

}

private static void replacePlaceholdersInParagraph(XWPFParagraph paragraph, Map placeholders) {

String text = paragraph.getText();

if (text != null && !text.isEmpty()) {

for (Map.Entry entry : placeholders.entrySet()) {

if (text.contains(entry.getKey())) {

text = text.replace(entry.getKey(), entry.getValue());

}

}

// 清空原有段落内容,并重新写入替换后的文本

for (int i = paragraph.getRuns().size() - 1; i >= 0; i--) {

paragraph.removeRun(i);

}

paragraph.createRun().setText(text);

}

}

}

弓箭射箭入坑如何选择反曲弓器材! 率土之滨多久一个赛季