在企业开发中,Excel 几乎无处不在:
- 数据导入(批量导入用户、工单、设备)
- 报表导出(运营报表、财务报表)
- 数据交换(系统之间通过 Excel 交互)
如果使用 Java 开发系统,最常见的解决方案就是:
Apache POI
而在 POI 中,最核心的类之一就是:
java
org.apache.poi.xssf.usermodel.XSSFWorkbook
下面我们详细展开。
一、Apache POI 是什么
Apache POI 是 Apache 开源的一个 Java 操作 Office 文件的库。
支持:
| Office文件 | POI组件 |
|---|---|
Excel 2003 .xls |
HSSF |
Excel 2007+ .xlsx |
XSSF |
Word .docx |
XWPF |
| PowerPoint | XSLF |
本文重点介绍:
java
XSSFWorkbook
含义:
XSSF = XML Spreadsheet Format
即:
用于操作 Excel
.xlsx文件的 Java API
二、Excel 的对象结构
Excel 文件其实是一个 层级结构:
Workbook(工作簿)
├── Sheet(工作表)
│ ├── Row(行)
│ │ ├── Cell(单元格)
Apache POI 的类结构:
| Excel概念 | POI类 |
|---|---|
| 工作簿 | XSSFWorkbook |
| 工作表 | XSSFSheet |
| 行 | XSSFRow |
| 单元格 | XSSFCell |
对象关系:
XSSFWorkbook
└── XSSFSheet
└── XSSFRow
└── XSSFCell
因此:
XSSFWorkbook 就是整个 Excel 文件的 Java 对象表示。
三、Excel 文件的真实结构(核心原理)
大家或许不知道:
.xlsx本质上是一个 ZIP 文件。
我们可以直接解压:
example.xlsx
得到:
example.xlsx
├── [Content_Types].xml
├── _rels/
├── xl/
│ ├── workbook.xml
│ ├── worksheets/
│ │ ├── sheet1.xml
│ │ ├── sheet2.xml
│ ├── styles.xml
│ ├── sharedStrings.xml
核心结构:
| 文件 | 作用 |
|---|---|
| workbook.xml | 工作簿信息 |
| sheet.xml | 工作表 |
| sharedStrings.xml | 字符串池 |
| styles.xml | 样式 |
POI 的工作流程:
Excel文件
↓
解压 ZIP
↓
解析 XML
↓
构建 Java 对象
最终形成:
XSSFWorkbook
└── XSSFSheet
└── XSSFRow
└── XSSFCell
四、引入 Apache POI 依赖
Maven 依赖:
xml
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.5</version>
</dependency>
核心组件:
poi
poi-ooxml
xmlbeans
commons-compress
五、读取 Excel(最常见场景)
典型场景:
- 用户上传 Excel
- 解析数据
- 写入数据库
示例 Excel:
users.xlsx
ID | Name | Age
1 | Tom | 20
2 | Jack | 22
Java 读取代码:
java
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;
public class ExcelReader {
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("users.xlsx");
XSSFWorkbook workbook = new XSSFWorkbook(fis);
Sheet sheet = workbook.getSheetAt(0);
for (Row row : sheet) {
for (Cell cell : row) {
System.out.print(cell.toString() + " ");
}
System.out.println();
}
workbook.close();
fis.close();
}
}
输出:
ID Name Age
1 Tom 20
2 Jack 22
六、Excel 精确读取
实际开发中需要:
- 跳过标题
- 判断类型
- 处理空值
示例:
java
for (int i = 1; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
if (row == null) {
continue;
}
Cell idCell = row.getCell(0);
Cell nameCell = row.getCell(1);
Cell ageCell = row.getCell(2);
int id = (int) idCell.getNumericCellValue();
String name = nameCell.getStringCellValue();
int age = (int) ageCell.getNumericCellValue();
System.out.println(id + " " + name + " " + age);
}
输出:
1 Tom 20
2 Jack 22
七、创建 Excel 文件
除了读取,还可以 生成 Excel 报表。
示例:
java
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileOutputStream;
public class ExcelWriter {
public static void main(String[] args) throws Exception {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Users");
Row header = sheet.createRow(0);
header.createCell(0).setCellValue("ID");
header.createCell(1).setCellValue("Name");
header.createCell(2).setCellValue("Age");
Row row1 = sheet.createRow(1);
row1.createCell(0).setCellValue(1);
row1.createCell(1).setCellValue("Tom");
row1.createCell(2).setCellValue(20);
FileOutputStream fos = new FileOutputStream("users.xlsx");
workbook.write(fos);
fos.close();
workbook.close();
}
}
生成 Excel:
users.xlsx
ID | Name | Age
1 | Tom | 20
八、SpringBoot Excel 导出接口
真实系统中,通常通过 HTTP 下载 Excel。
示例:
java
@GetMapping("/export")
public void export(HttpServletResponse response) throws Exception {
XSSFWorkbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Users");
Row header = sheet.createRow(0);
header.createCell(0).setCellValue("ID");
header.createCell(1).setCellValue("Name");
Row row = sheet.createRow(1);
row.createCell(0).setCellValue(1);
row.createCell(1).setCellValue("Tom");
response.setContentType(
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader(
"Content-Disposition",
"attachment;filename=users.xlsx");
workbook.write(response.getOutputStream());
workbook.close();
}
浏览器会下载:
users.xlsx
九、大文件 Excel 的内存问题
如果 Excel 很大:
100万行
使用XSSFWorkbook会全部加载到内存,可能导致:
OutOfMemoryError
原因:
POI 会把所有 Cell 对象加载到 JVM
十、大文件解决方案:SXSSFWorkbook
POI 提供了:
SXSSFWorkbook
特点:
| 特点 | 说明 |
|---|---|
| 流式写入 | 不全部加载 |
| 低内存 | 适合百万级 |
| 滑动窗口 | 自动清理 |
示例:
java
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
SXSSFWorkbook workbook = new SXSSFWorkbook(100);
含义:
只保留 100 行在内存
生成百万数据:
java
for (int i = 0; i < 1000000; i++) {
Row row = sheet.createRow(i);
row.createCell(0).setCellValue(i);
}
十一、Excel 导入最佳实践
生产环境建议:
1 跳过空行
java
if (row == null) {
continue;
}
2 判断单元格类型
java
switch (cell.getCellType()) {
case STRING:
value = cell.getStringCellValue();
break;
case NUMERIC:
value = cell.getNumericCellValue();
break;
}
3 统一读取工具
建议封装:
java
public static String getCellValue(Cell cell)
避免大量判断。
十二、XSSFWorkbook vs HSSFWorkbook
| 类 | Excel版本 | 文件格式 |
|---|---|---|
| HSSFWorkbook | Excel 2003 | .xls |
| XSSFWorkbook | Excel 2007+ | .xlsx |
区别:
| 特点 | HSSF | XSSF |
|---|---|---|
| 最大行 | 65536 | 1048576 |
| 最大列 | 256 | 16384 |
| 文件格式 | 二进制 | XML |
现代系统 基本全部使用 XSSFWorkbook。
十三、总结
XSSFWorkbook 的本质:
Excel
.xlsx文件在 Java 中的对象表示。
核心结构:
XSSFWorkbook
↓
XSSFSheet
↓
XSSFRow
↓
XSSFCell
常见用途:
| 场景 | 说明 |
|---|---|
| Excel 导入 | 解析数据 |
| Excel 导出 | 生成报表 |
| 数据交换 | 系统间导入导出 |
关键注意点:
- 大文件使用 SXSSFWorkbook
- 注意 Cell 类型判断
- 建议封装 读取工具类