为什么选择 Apache POI?
- 成熟稳定:Apache POI 是一个老牌的开源项目,经过大量项目验证,非常稳定。
- 功能全面:支持读写 Excel (
.xls,.xlsx)、Word (.doc,.docx)、PowerPoint (.ppt,.pptx) 等多种 Office 格式。 - 社区活跃:遇到问题很容易找到解决方案。
.xlsx支持:使用其XSSF(XML SpreadSheet Format) API 来专门处理.xlsx格式。
环境搭建 (Maven 依赖)
你需要在你的项目中添加 Apache POI 的依赖,对于 .xlsx 格式,我们主要需要 poi-ooxml 这个依赖。

在你的 pom.xml 文件中添加以下内容:
<dependencies>
<!-- 核心依赖 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.5</version> <!-- 建议使用较新版本 -->
</dependency>
<!-- 用于处理 .xlsx 格式的核心依赖 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.5</version>
</dependency>
<!-- 用于处理 XML 的依赖,poi-ooxml 会自动引入,但明确写上更清晰 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.4</version>
</dependency>
<!-- (可选) 如果涉及到日期格式化等,可能需要 commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
</dependencies>
基础代码示例:导出简单的 Excel 表格
下面是一个最基础的示例,创建一个 .xlsx 文件,写入一些数据,并下载到浏览器。
1 核心类说明
XSSFWorkbook: 代表一个.xlsx格式的 Excel 工作簿。XSSFSheet: 代表工作簿中的一张工作表。XSSFRow: 代表工作表中的一行。XSSFCell: 代表一行中的一个单元格。XSSFCellStyle: 定义单元格的样式(如字体、颜色、边框、对齐方式等)。
2 完整代码示例
这个例子演示了如何创建一个工作簿,写入表头和数据,并设置一些基本样式。
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ExcelExportDemo {
public static void main(String[] args) {
// 1. 创建一个 Excel 工作簿
Workbook workbook = new XSSFWorkbook();
// 2. 创建一个工作表,名为 "用户数据"
Sheet sheet = workbook.createSheet("用户数据");
// 3. 创建标题行 (第一行)
Row headerRow = sheet.createRow(0);
// 4. 创建单元格并设置标题
String[] headers = {"ID", "姓名", "年龄", "邮箱", "创建日期"};
for (int i = 0; i < headers.length; i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(headers[i]);
}
// 5. 准备一些数据
List<Object[]> data = new ArrayList<>();
data.add(new Object[]{1, "张三", 28, "zhangsan@example.com", "2025-10-27"});
data.add(new Object[]{2, "李四", 32, "lisi@example.com", "2025-10-26"});
data.add(new Object[]{3, "王五", 24, "wangwu@example.com", "2025-10-25"});
data.add(new Object[]{4, "赵六", 45, "zhaoliu@example.com", "2025-10-24"});
// 6. 写入数据行
for (int i = 0; i < data.size(); i++) {
Row dataRow = sheet.createRow(i + 1); // 从第二行开始
Object[] rowData = data.get(i);
for (int j = 0; j < rowData.length; j++) {
Cell cell = dataRow.createCell(j);
// 设置单元格值,可以根据类型优化
cell.setCellValue(rowData[j].toString());
}
}
// 7. 自动调整列宽,使内容显示完整
for (int i = 0; i < headers.length; i++) {
sheet.autoSizeColumn(i);
}
// 8. 将工作簿写入文件
try (FileOutputStream fileOut = new FileOutputStream("users.xlsx")) {
workbook.write(fileOut);
System.out.println("Excel 文件 'users.xlsx' 已成功生成!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 9. 关闭工作簿,释放资源
try {
if (workbook != null) {
workbook.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行这段代码后,你会在项目根目录下生成一个 users.xlsx 文件,内容如下:

| ID | 姓名 | 年龄 | 邮箱 | 创建日期 |
|---|---|---|---|---|
| 1 | 张三 | 28 | zhangsan@example.com | 2025-10-27 |
| 2 | 李四 | 32 | lisi@example.com | 2025-10-26 |
| 3 | 王五 | 24 | wangwu@example.com | 2025-10-25 |
| 4 | 赵六 | 45 | zhaoliu@example.com | 2025-10-24 |
进阶功能与最佳实践
1 设置单元格样式(字体、颜色、边框)
// 创建一个样式对象
CellStyle style = workbook.createCellStyle();
// 1. 设置字体
Font font = workbook.createFont();
font.setFontName("Arial");
font.setFontHeightInPoints((short) 12); // 字号
font.setBold(true); // 加粗
style.setFont(font);
// 2. 设置背景色
style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
// 3. 设置边框
style.setBorderTop(BorderStyle.THIN);
style.setBorderBottom(BorderStyle.THIN);
style.setBorderLeft(BorderStyle.THIN);
style.setBorderRight(BorderStyle.THIN);
// 4. 设置对齐方式
style.setAlignment(HorizontalAlignment.CENTER); // 水平居中
style.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中
// 将样式应用到单元格
Cell cell = headerRow.createCell(0);
cell.setCellValue("ID");
cell.setCellStyle(style);
2 处理日期格式
日期在 Excel 中需要特殊处理,否则会显示成一串数字。
// 创建日期格式
CreationHelper createHelper = workbook.getCreationHelper();
CellStyle dateStyle = workbook.createCellStyle();
dateStyle.setDataFormat(createHelper.createDataFormat().getFormat("yyyy-MM-dd HH:mm:ss"));
// 写入日期数据
Cell dateCell = dataRow.createCell(4);
// 假设 date 是一个 java.util.Date 对象
dateCell.setCellValue(new java.util.Date());
dateCell.setCellStyle(dateStyle);
3 在 Web 应用中下载(Spring Boot 示例)
这是最常见的应用场景,当用户点击“导出”按钮时,浏览器直接下载 Excel 文件,而不是在服务器上生成文件。
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@Controller
public class ExcelDownloadController {
@GetMapping("/download")
public void downloadExcel(HttpServletResponse response) throws IOException {
// 1. 创建工作簿和数据 (同上)
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("用户数据");
// ... (填充表头和数据,可以复用上面的代码逻辑)
// 2. 设置响应头
String fileName = "用户列表_" + System.currentTimeMillis() + ".xlsx";
// 处理中文文件名,防止乱码
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"; filename*=utf-8''" + encodedFileName);
// 3. 将 Excel 写入响应输出流
try (ServletOutputStream outputStream = response.getOutputStream()) {
workbook.write(outputStream);
workbook.close();
}
}
}
大数据量导出优化(SXSSF)
如果需要导出的数据量非常大(比如几十万行),使用 XSSFWorkbook 会导致内存溢出(OOM),因为它会将所有数据都加载到内存中。
这时,你应该使用 SXSSF (Streaming Usermodel for XSSF),它的核心思想是将数据写入临时文件,只保留一部分在内存中,从而极大地降低内存消耗。

1 SXSSF 与 XSSF 的主要区别
- 内存友好:
SXSSFWorkbook会创建一个临时的磁盘文件(poi-sxssf-sheet.xml),当内存中的行数超过一个阈值(rowAccessWindowSize)时,最旧的一行就会被“刷”到磁盘上,释放内存。 - 只读:
SXSSF是一个流式 API,一旦数据被写入磁盘并刷新,就不能再修改它。 - API 兼容:
SXSSF的 API 与XSSF高度兼容,大部分代码可以无缝切换。
2 SXSSF 示例
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import java.io.FileOutputStream;
import java.io.IOException;
public class LargeDataExportDemo {
public static void main(String[] args) throws IOException {
// 1. 创建 SXSSFWorkbook,参数是内存中保留的行数,超过的会写入磁盘
// 如果设置为 -1,则等同于 XSSFWorkbook,所有数据都在内存中
Workbook workbook = new SXSSFWorkbook(100); // 内存中只保留100行
Sheet sheet = workbook.createSheet("大数据表");
// 2. 写入大量数据 (10 万行)
for (int rownum = 0; rownum < 100000; rownum++) {
Row row = sheet.createRow(rownum);
for (int cellnum = 0; cellnum < 10; cellnum++) {
Cell cell = row.createCell(cellnum);
cell.setCellValue("Row " + rownum + ", Cell " + cellnum);
}
// 每 1000 行打印一次进度
if (rownum % 1000 == 0) {
System.out.println("已处理 " + rownum + " 行");
}
}
// 3. 清理临时文件 (非常重要!)
((SXSSFWorkbook) workbook).dispose();
// 4. 写入最终文件
try (FileOutputStream out = new FileOutputStream("large_data.xlsx")) {
workbook.write(out);
}
System.out.println("大数据 Excel 文件已生成!");
}
}
注意:使用 SXSSFWorkbook 后,一定要在最后调用 dispose() 方法来删除所有临时文件,否则磁盘空间会被占满。
| 场景 | 推荐库 | 特点 |
|---|---|---|
导出 .xlsx 文件 |
XSSFWorkbook |
功能全面,可读可写,适合中小数据量(万行以内)。 |
| Web 下载 | XSSFWorkbook + HttpServletResponse |
标准做法,将内存中的 Excel 流式输出到浏览器。 |
| 大数据量导出 | SXSSFWorkbook |
内存友好,避免 OOM,适合几十万甚至上百万行数据。 |
读取 .xlsx 文件 |
XSSFWorkbook / SXSSFWorkbook |
读取时,如果文件不大用 XSSFWorkbook;如果文件很大且需要快速读取,可以用 SXSSF 的只读模式。 |
希望这份详细的指南能帮助你掌握在 Java 中导出 Excel 2007 文件!
