核心依赖 (Maven)
你需要在你的 pom.xml 文件中添加 Apache POI 的依赖,对于 Excel 2007 (.xlsx),你需要使用 poi-ooxml 模块。
<dependencies>
<!-- 核心依赖 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.4</version> <!-- 建议使用较新版本 -->
</dependency>
<!-- 用于处理 .xlsx 格式的依赖 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.4</version>
</dependency>
<!-- 为了支持 XML 和其他格式,可能还需要这个 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-lite</artifactId>
<version>5.2.4</version>
</dependency>
</dependencies>
基础示例:创建一个简单的 .xlsx 文件
这个示例将演示如何创建一个工作簿,添加一个工作表,写入数据,并保存到本地文件。
代码实现
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileOutputStream;
import java.io.IOException;
public class BasicExcelExport {
public static void main(String[] args) {
// 1. 创建一个新的 XSSFWorkbook 对象,代表一个 .xlsx 文件
Workbook workbook = new XSSFWorkbook();
try {
// 2. 创建一个工作表,命名为 "员工信息"
Sheet sheet = workbook.createSheet("员工信息");
// 3. 创建标题行(第0行)
Row headerRow = sheet.createRow(0);
// 设置标题
headerRow.createCell(0).setCellValue("ID");
headerRow.createCell(1).setCellValue("姓名");
headerRow.createCell(2).setCellValue("部门");
headerRow.createCell(3).setCellValue("入职日期");
// 4. 创建数据行
// 第一行数据
Row dataRow1 = sheet.createRow(1);
dataRow1.createCell(0).setCellValue(1);
dataRow1.createCell(1).setCellValue("张三");
dataRow1.createCell(2).setCellValue("研发部");
dataRow1.createCell(3).setCellValue(setDateValue(workbook, "2025-01-15")); // 设置日期格式
// 第二行数据
Row dataRow2 = sheet.createRow(2);
dataRow2.createCell(0).setCellValue(2);
dataRow2.createCell(1).setCellValue("李四");
dataRow2.createCell(2).setCellValue("市场部");
dataRow2.createCell(3).setCellValue(setDateValue(workbook, "2025-05-20"));
// 5. 自动调整列宽,使内容显示完整
for (int i = 0; i < 4; i++) {
sheet.autoSizeColumn(i);
}
// 6. 定义文件输出路径
String filePath = "D:/temp/员工信息.xlsx";
// 7. 将工作簿写入到文件
try (FileOutputStream fileOut = new FileOutputStream(filePath)) {
workbook.write(fileOut);
System.out.println("Excel 文件生成成功!路径: " + filePath);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 8. 关闭工作簿,释放资源
try {
if (workbook != null) {
workbook.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 设置单元格为日期格式
* @param workbook 工作簿对象
* @param dateString 日期字符串 (yyyy-MM-dd)
* @return CellStyle 设置好样式的单元格
*/
private static CellStyle setDateValue(Workbook workbook, String dateString) {
// 创建单元格样式
CellStyle dateStyle = workbook.createCellStyle();
// 创建数据格式
CreationHelper createHelper = workbook.getCreationHelper();
// 设置日期格式为 "yyyy-MM-dd"
dateStyle.setDataFormat(createHelper.createDataFormat().getFormat("yyyy-MM-dd"));
// 创建一个临时单元格来应用样式
// 注意:这个单元格不会被写入最终文件,仅用于样式设置
Cell tempCell = workbook.createSheet("temp").createRow(0).createCell(0);
tempCell.setCellStyle(dateStyle);
// 设置日期值,POI会自动处理
tempCell.setCellValue(java.sql.Date.valueOf(dateString));
// 返回创建好的样式
return dateStyle;
}
}
代码解释
-
Workbook workbook = new XSSFWorkbook();Workbook是 POI 中表示 Excel 文件的顶级接口。XSSFWorkbook是专门用于操作.xlsx(Excel 2007+) 格式的实现类。
-
Sheet sheet = workbook.createSheet("员工信息");Sheet代表 Excel 文件中的一个工作表(Sheet)。createSheet()方法用于创建一个新的工作表,并可以指定其名称。
-
Row row = sheet.createRow(0);Row代表工作表中的一行。createRow()用于创建一行,参数是行索引(从 0 开始)。
-
Cell cell = row.createCell(0);Cell代表行中的一个单元格。createCell()用于创建一个单元格,参数是列索引(从 0 开始)。
-
cell.setCellValue("张三");setCellValue()方法用于向单元格中设置值,POI 支持多种数据类型,如String,Integer,Double,Date等。
-
CellStyle和DataFormatCellStyle用于定义单元格的样式,如字体、颜色、边框、对齐方式以及数据格式。- 要设置日期格式,需要先获取
CreationHelper,然后创建DataFormat对象,并调用getFormat()方法传入格式字符串(如"yyyy-MM-dd")。 - 最后将创建的
CellStyle应用到单元格上。
-
sheet.autoSizeColumn(i);这是一个非常实用的方法,可以根据列内容自动调整列宽,避免内容被截断。
-
FileOutputStream和workbook.write()- 使用
FileOutputStream指定一个输出路径。 - 调用
workbook.write(fileOut)将内存中的Workbook对象写入到文件流中。
- 使用
-
try-with-resources和workbook.close()- 最佳实践:
Workbook对象会占用大量内存,使用完毕后必须关闭以释放资源。 - 推荐使用
try-with-resources语句(如try (FileOutputStream ...)),它可以自动关闭实现了AutoCloseable接口(如FileOutputStream和XSSFWorkbook)的资源,即使在发生异常时也能确保关闭。
- 最佳实践:
进阶示例:Web 项目中下载 Excel
在实际的 Web 应用(如 Spring Boot 项目)中,我们通常不是将文件保存到服务器磁盘,而是直接通过 HTTP 响应让用户下载。
代码实现 (以 Spring Boot 为例)
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@RestController
public class ExcelDownloadController {
@GetMapping("/download-excel")
public void downloadExcel(HttpServletResponse response) throws IOException {
// 1. 创建工作簿和工作表
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("产品列表");
// 2. 创建标题行
Row headerRow = sheet.createRow(0);
headerRow.createCell(0).setCellValue("产品ID");
headerRow.createCell(1).setCellValue("产品名称");
headerRow.createCell(2).setCellValue("价格");
// 3. 创建数据行
for (int i = 1; i <= 10; i++) {
Row row = sheet.createRow(i);
row.createCell(0).setCellValue(i);
row.createCell(1).setCellValue("产品 " + i);
row.createCell(2).setCellValue(10.0 * i);
}
// 4. 自动调整列宽
for (int i = 0; i < 3; i++) {
sheet.autoSizeColumn(i);
}
// 5. 设置响应头
// 设置 Content-Type,告诉浏览器这是一个要下载的文件
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
// 设置 Content-Disposition,指定文件名和下载方式
String fileName = "产品列表_" + System.currentTimeMillis() + ".xlsx";
// 对文件名进行 URL 编码,防止中文乱码
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"; filename*=utf-8''" + encodedFileName);
// 6. 写入响应输出流
try (OutputStream out = response.getOutputStream()) {
workbook.write(out);
workbook.close();
}
}
}
Web 下载关键点
-
response.setContentType(...)- 必须设置为 Excel 2007 的 MIME 类型:
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet。
- 必须设置为 Excel 2007 的 MIME 类型:
-
response.setHeader("Content-Disposition", ...)attachment:表示这是一个附件,浏览器会触发下载对话框而不是直接在浏览器中打开。filename="...":指定下载时显示的文件名。- URLEncoder.encode():如果文件名包含中文,必须进行 URL 编码,否则在不同浏览器下可能会出现乱码。
-
response.getOutputStream()- 获取
HttpServletResponse的输出流,将Workbook写入这个流中,数据就会直接发送给浏览器。
- 获取
高级功能与最佳实践
1 使用样式美化单元格
// 在创建 Workbook 后
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 = sheet.createRow(0).createCell(0);
cell.setCellValue("这是一个标题");
cell.setCellStyle(style);
2 合并单元格
// 合并从 (0, 0) 到 (4, 0) 的区域 sheet.addMergedRegion(new CellRangeAddress(0, 4, 0, 0));
3 性能优化(大数据量导出)
当导出数据量非常大(例如几十万行)时,将所有数据一次性加载到内存中的 XSSFWorkbook 会导致 OutOfMemoryError,这时,应使用 SXSSFWorkbook(流 API)。
SXSSFWorkbook 是基于 XSSFWorkbook 的,它会在写入磁盘后,将不活跃的行从内存中移除,从而保持一个较小的内存占用。
示例代码:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFRow;
import java.io.FileOutputStream;
import java.io.IOException;
public class LargeDataExport {
public static void main(String[] args) throws IOException {
// 1. 创建 SXSSFWorkbook,参数 100 表示在内存中保留的行数
Workbook workbook = new SXSSFWorkbook(100);
Sheet sheet = workbook.createSheet("大数据量");
// 2. 写入 100,000 行数据
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) {
((SXSSFSheet) sheet).flushRows();
}
}
// 3. 写入文件
try (FileOutputStream out = new FileOutputStream("D:/temp/large_data.xlsx")) {
workbook.write(out);
}
// 4. 关闭 workbook,会清理掉临时文件
((SXSSFWorkbook) workbook).dispose();
}
}
注意:SXSSFWorkbook 不支持所有 XSSFWorkbook 的功能(例如部分图表和公式),但在处理纯数据导出时,它是性能最优的选择。
| 功能 | 核心类 | 适用场景 |
|---|---|---|
| 基础创建 | XSSFWorkbook |
创建 .xlsx 文件,写入少量到中等量数据。 |
| Web 下载 | XSSFWorkbook + HttpServletResponse |
在 Web 应用中提供文件下载功能。 |
| 样式美化 | CellStyle, Font, Border |
对 Excel 的外观进行定制。 |
| 大数据量 | SXSSFWorkbook |
导出海量数据(万行以上),防止内存溢出。 |
| 旧版 Excel | HSSFWorkbook |
用于导出 .xls (Excel 97-2003) 格式。 |
对于绝大多数 Java 项目,Apache POI 是导出 Excel 的首选,掌握 XSSFWorkbook 和 SXSSFWorkbook 的用法,以及样式和 Web 下载的技巧,就能应对绝大多数导出需求。
