POI 讲解

一、POI 是什么?

Apache POI 是 Apache 基金会提供的一套 Java 操作 Office 文档的开源库,主要支持:

  • Excel(.xls / .xlsx)
  • Word(.doc / .docx)
  • PowerPoint
  • Visio
  • Outlook

其中最常用的就是 Excel 操作

二、为什么要用 POI?

因为在企业开发中,Excel 是最常见的数据交换格式,比如:

  • 导出报表(订单报表、财务报表)
  • 导入数据(批量导入用户、批量导入商品)
  • 模板导出(固定模板 + 动态数据)
  • 数据备份
  • 批量生成合同、发票等文档

Java 本身没有提供操作 Excel 的能力,所以必须依赖 POI。

三、POI 支持的 Excel 格式

POI 支持两种 Excel 格式:

  1. HSSF ------ 操作 .xls(Excel 97-2003)

    • 最多 65536 行
    • 最多 256 列
  2. XSSF ------ 操作 .xlsx(Excel 2007+)

    • 最多 1,048,576 行
    • 最多 16,384 列
    • 推荐使用
  3. SXSSF ------ 大数据量导出(百万级)

    • 基于 XSSF,但使用 流式处理
    • 适合导出几十万、几百万行数据
    • 内存占用极低

四、POI 核心对象模型

POI 操作 Excel 的核心对象如下(非常重要):

  • Workbook(工作簿) → 对应整个 Excel 文件 ,创建 / 读取 Excel 的入口对象
    • XSSF 格式:XSSFWorkbook workbook = new XSSFWorkbook();
  • Sheet(工作表) → 对应 Excel 里的一个 sheet 页签 ,一个 Workbook 可以创建多个 Sheet
    • 创建:Sheet sheet = workbook.createSheet("用户报表");
    • 获取:Sheet sheet = workbook.getSheetAt(0); // 获取第一个 sheet
  • Row(行) → 对应 Sheet 中的一行数据 ,行索引从0开始(0 是表头行)
    • 创建:Row row = sheet.createRow(0); // 创建第 1 行
    • 获取:Row row = sheet.getRow(1); // 获取第 2 行
  • Cell(单元格) → 对应 Row 中的一个单元格 ,列索引从0开始
    • 创建:Cell cell = row.createCell(0); // 创建当前行的第 1 列单元格
    • 获取:Cell cell = row.getCell(1); // 获取当前行的第 2 列单元格
  • 辅助对象:CellStyle(单元格样式)、Font(字体样式)→ 用于设置单元格的字体、颜色、对齐方式、边框等
  • 核心层级关系:Workbook → Sheet → Row → Cell

五、POI 读写 Excel 实战

引入依赖:

java 复制代码
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>

写入 Excel(导出)

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

import java.io.FileOutputStream;
import java.io.IOException;

public class ExcelWriter {
    public static void main(String[] args) throws IOException {
        // 1. 创建 Workbook
        Workbook workbook = new XSSFWorkbook();

        // 2. 创建 Sheet
        Sheet sheet = workbook.createSheet("用户列表");

        // 3. 创建表头行
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("ID");
        headerRow.createCell(1).setCellValue("姓名");
        headerRow.createCell(2).setCellValue("年龄");

        // 4. 写入数据
        Object[][] data = {
                {1, "张三", 20},
                {2, "李四", 22},
                {3, "王五", 25}
        };

        int rowIndex = 1;
        for (Object[] rowData : data) {
            Row row = sheet.createRow(rowIndex++);
            row.createCell(0).setCellValue((Integer) rowData[0]);
            row.createCell(1).setCellValue((String) rowData[1]);
            row.createCell(2).setCellValue((Integer) rowData[2]);
        }

        // 5. 输出到文件
        try (FileOutputStream outputStream = new FileOutputStream("users.xlsx")) {
            workbook.write(outputStream);
        }

        System.out.println("Excel 生成成功!");
    }
}

读取 Excel(导入)

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

import java.io.FileInputStream;
import java.io.IOException;

public class ExcelReader {
    public static void main(String[] args) throws IOException {
        // 1. 读取文件
        try (FileInputStream inputStream = new FileInputStream("users.xlsx");
             Workbook workbook = new XSSFWorkbook(inputStream)) {

            // 2. 获取 Sheet
            Sheet sheet = workbook.getSheetAt(0);

            // 3. 遍历行
            for (Row row : sheet) {
                // 4. 遍历单元格
                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();
            }
        }
    }
}
相关推荐
学长毕业设计1 小时前
基于SpringBoot的公益基金管理系统(源码+文档+讲解视频)
java·spring boot·后端
东小西1 小时前
【SAA实战】第 3 篇 · 工具调用全攻略:把业务能力交给 Agent 自己调度
java·后端·spring
东小西1 小时前
【SAA实战】第 4 篇 · Agent 短期记忆:saver 让 Agent 跨轮记得住(threadId 隔离)
java·后端·spring
许彰午1 小时前
22-DataCenter报文序列化
java·低代码·架构·状态模式
2601_962065251 小时前
[MySQL] SQL优化之性能分析
java·sql·mysql
小范同学_2 小时前
JDK1.7 与 JDK1.8 HashMap 底层原理对比 + 数组并发扩容死循环详解
java·开发语言
予昊3 小时前
从零实现“在线五子棋对战“:WebSocket 实时通信 + 段位匹配
java·开发语言·网络·websocket
2601_962203513 小时前
【SpringAI入门】初识SpringAI
java
weixin_461408583 小时前
Mybatis-flex小记
java·开发语言·mybatis
2601_962177134 小时前
【MySQL篇】聚合查询,联合查询
android·java·mysql