Apache POI 常用操作指南

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();
        }
    }
}

代码说明

  1. 创建工作簿和工作表
    • 使用 XSSFWorkbook 创建一个 .xlsx 文件。
    • 使用 createSheet 方法创建一个工作表。
  2. 写入数据
    • 表头部分:通过 createRowcreateCell 创建行和单元格。
    • 数据部分:通过嵌套循环写入多行多列的数据。
  3. 自动调整列宽
    • sheet.autoSizeColumn(i) 方法可以根据内容动态调整列宽。
  4. 保存文件
    • 使用 FileOutputStream 将工作簿写入文件。
  5. 关闭资源
    • POI 提供的工作簿资源需要在使用完后关闭,以避免内存泄漏

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

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

示例代码:格式化 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 静态数据下拉

实现步骤

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

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

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 级联数据下拉

实现思路

  1. 准备静态数据:定义第一个下拉列表的选项(如:类别),并准备对应的第二级选项(子项)。
  2. 动态关联:使用 Excel 的 Named Range(名称管理器)将第二级选项与第一级选项动态关联。
  3. 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 文档,包括:

  1. XWPFDocument:表示整个 Word 文档。
  2. XWPFParagraph:表示段落。
  3. XWPFRun:表示段落中的文本片段,可以设置字体、大小、加粗、颜色等。
  4. XWPFTable:表示表格。
  5. 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();
        }
    }
}

代码解析

  1. 创建文档
    XWPFDocument document = new XWPFDocument();
    • 这是 Word 操作的入口,创建一个空白的 .docx 文档。
  2. 添加段落
    • 通过 document.createParagraph() 方法创建一个段落。
  3. 向段落中添加文本
    • 使用 XWPFRun run = paragraph.createRun(); 添加文本片段。
    • 可设置样式,如:字体、大小、加粗、颜色等。
  4. 保存文档
    • 通过 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 文档中。
图片格式支持PNGJPGGIFBMP 等。

示例代码:向 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 文档内容的读取分为两种情况:

  1. .docx 文件(基于 XML 格式,使用 XWPFDocument)。
  2. .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固定模板占位符替换(扩展)

占位符替换的实现原理

  1. 创建 Word 模板
    在 Word 文档中使用占位符,例如:${name}${date}${title} 等。
  2. 加载 Word 文档
    使用 XWPFDocument 读取模板文件。
  3. 替换占位符
    遍历文档中的所有段落和表格单元格,将占位符替换为实际值。
  4. 保存新文档
    将替换后的 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);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值