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
<!-- Apache POI -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.2</version>
</dependency>
<!-- 解决依赖问题 -->
<!-- Commons IO -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.18.0</version>
</dependency>
<!-- Log4j -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.20.0</version>
</dependency>
测试依赖
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
文档。
- 这是 Word 操作的入口,创建一个空白的
- 添加段落:
- 通过
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<String, String> 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<String, String> placeholders) {
String text = paragraph.getText();
if (text != null && !text.isEmpty()) {
for (Map.Entry<String, String> 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);
}
}
}