一、Apache POI简介
Apache POI是Apache软件基金会的开源项目,全称"Poor Obfuscation Implementation"(简陋模糊化实现),主要用于Java程序对Microsoft Office格式文件(如Excel、Word、PowerPoint等)进行读写操作。
核心组件:
- HSSF:操作Excel 97-2003格式(.xls)
- XSSF:操作Excel 2007+格式(.xlsx)
- SXSSF:XSSF的流式API,适合大数据量
- HWPF:操作Word文档
- HSLF:操作PowerPoint
二、基础Excel导出实战
2.1 最小化示例(导出.xls)
java
// 创建Excel工作簿(HSSF对应.xls格式)
Workbook workbook = new HSSFWorkbook();
// 创建工作表
Sheet sheet = workbook.createSheet("员工表");
// 创建表头行(第0行)
Row headerRow = sheet.createRow(0);
headerRow.createCell(0).setCellValue("姓名");
headerRow.createCell(1).setCellValue("年龄");
headerRow.createCell(2).setCellValue("部门");
// 添加数据行(第1行)
Row dataRow = sheet.createRow(1);
dataRow.createCell(0).setCellValue("张三");
dataRow.createCell(1).setCellValue(28);
dataRow.createCell(2).setCellValue("研发部");
// 写入到文件
try (FileOutputStream fos = new FileOutputStream("员工表.xls")) {
workbook.write(fos);
}
2.2 新版Excel导出(.xlsx)
java
// 使用XSSFWorkbook创建.xlsx文件
Workbook workbook = new XSSFWorkbook();
// 其余操作与HSSF完全相同
2.3 添加简单样式
java
// 创建单元格样式
CellStyle headerStyle = workbook.createCellStyle();
Font headerFont = workbook.createFont();
headerFont.setBold(true); // 加粗
headerFont.setFontHeightInPoints((short)12); // 字号
headerStyle.setFont(headerFont);
headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); // 背景色
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
// 应用样式到表头
for (int i = 0; i < headerRow.getLastCellNum(); i++) {
headerRow.getCell(i).setCellStyle(headerStyle);
}
三、中级功能进阶
3.1 大数据量导出(SXSSF)
java
// 创建SXSSF工作簿(保留100行在内存中)
Workbook workbook = new SXSSFWorkbook(100);
try {
Sheet sheet = workbook.createSheet("大数据表");
// 写入10万行数据
for (int i = 0; i < 100000; i++) {
Row row = sheet.createRow(i);
row.createCell(0).setCellValue("数据" + i);
row.createCell(1).setCellValue(Math.random() * 100);
// 每1000行手动flush一次
if (i % 1000 == 0) {
((SXSSFSheet)sheet).flushRows(100); // 保留最近100行
}
}
// 写入文件
workbook.write(new FileOutputStream("大数据.xlsx"));
} finally {
// 必须显式清理临时文件
if (workbook instanceof SXSSFWorkbook) {
((SXSSFWorkbook)workbook).dispose();
}
}
3.2 合并单元格
java
// 合并A1到D1单元格
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 3));
// 创建合并单元格
Row mergedRow = sheet.createRow(0);
Cell mergedCell = mergedRow.createCell(0);
mergedCell.setCellValue("季度销售报表");
// 设置合并单元格样式
CellStyle mergedStyle = workbook.createCellStyle();
mergedStyle.setAlignment(HorizontalAlignment.CENTER);
mergedCell.setCellStyle(mergedStyle);
3.3 添加公式
java
// 添加SUM公式
Row formulaRow = sheet.createRow(sheet.getLastRowNum() + 1);
formulaRow.createCell(0).setCellValue("合计");
formulaRow.createCell(1).setCellFormula("SUM(B2:B" + (sheet.getLastRowNum()) + ")");
// 强制计算公式(可选)
workbook.getCreationHelper().createFormulaEvaluator().evaluateAll();
四、高级功能拓展
4.1 条件格式
java
// 创建条件格式规则
SheetConditionalFormatting scf = sheet.getSheetConditionalFormatting();
// 定义格式:数值大于90显示绿色背景
ConditionalFormattingRule rule = scf.createConditionalFormattingRule(
"B2>90");
PatternFormatting fill = rule.createPatternFormatting();
fill.setFillBackgroundColor(IndexedColors.LIGHT_GREEN.getIndex());
fill.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
// 应用范围:B2到B100
CellRangeAddress[] regions = { CellRangeAddress.valueOf("B2:B100") };
scf.addConditionalFormatting(regions, rule);
4.2 数据验证(下拉列表)
java
// 创建数据验证约束
DataValidationHelper dvHelper = sheet.getDataValidationHelper();
DataValidationConstraint dvConstraint = dvHelper.createExplicitListConstraint(
new String[]{"研发部","市场部","财务部","人事部"});
// 设置验证范围(C列)
CellRangeAddressList addressList = new CellRangeAddressList(
1, 100, 2, 2); // 从第2行到101行,第3列
// 创建数据验证
DataValidation validation = dvHelper.createValidation(dvConstraint, addressList);
validation.setShowErrorBox(true);
sheet.addValidationData(validation);
4.3 图表生成
java
// 创建绘图对象
Drawing<?> drawing = sheet.createDrawingPatriarch();
// 定义图表位置
ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 5, 1, 10, 15);
// 创建柱状图
Chart chart = drawing.createChart(anchor);
ChartLegend legend = chart.getOrCreateLegend();
legend.setPosition(LegendPosition.BOTTOM);
// 定义数据源
BarChartData data = chart.getChartDataFactory().createBarChartData(
ChartAxisFactory.createValueAxis(chart),
ChartAxisFactory.createCategoryAxis(chart)
);
// 设置系列数据
ChartDataSource<String> cats = DataSources.fromStringCellRange(
sheet, new CellRangeAddress(1, 4, 0, 0));
ChartDataSource<Number> values = DataSources.fromNumericCellRange(
sheet, new CellRangeAddress(1, 4, 1, 1));
data.addSeries(cats, values, "部门业绩");
// 应用数据到图表
chart.plot(data);
五、实际应用技巧
5.1 性能优化建议
-
对象复用:重复使用CellStyle对象
java// 错误的做法:每次循环都创建新样式 // 正确的做法:预先创建样式对象并复用 CellStyle dataStyle = workbook.createCellStyle(); for (Row row : sheet) { for (Cell cell : row) { cell.setCellStyle(dataStyle); } }
-
批量写入:使用SXSSF处理大数据
java// 设置窗口大小(内存中保留的行数) SXSSFWorkbook workbook = new SXSSFWorkbook(100);
-
及时清理:处理完成后释放资源
javatry { // 操作workbook... } finally { if (workbook instanceof SXSSFWorkbook) { ((SXSSFWorkbook)workbook).dispose(); } }
5.2 常见问题解决方案
问题1:导出文件损坏
- 确保正确关闭流
- 使用try-with-resources语句块
问题2:内存溢出
- 对于大数据量使用SXSSF
- 设置合理的flush间隔
问题3:日期格式问题
java
CellStyle dateStyle = workbook.createCellStyle();
CreationHelper createHelper = workbook.getCreationHelper();
dateStyle.setDataFormat(createHelper.createDataFormat().getFormat("yyyy-MM-dd"));
cell.setCellValue(new Date());
cell.setCellStyle(dateStyle);
六、扩展应用场景
6.1 与Web集成(Spring Boot示例)
java
@GetMapping("/export")
public void exportExcel(HttpServletResponse response) throws IOException {
// 设置响应头
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=export.xlsx");
// 创建Excel
Workbook workbook = new XSSFWorkbook();
// ...填充数据
// 写入响应流
workbook.write(response.getOutputStream());
workbook.close();
}
6.2 读取Excel数据
java
public List<Employee> readExcel(File file) throws IOException {
List<Employee> employees = new ArrayList<>();
try (Workbook workbook = WorkbookFactory.create(file)) {
Sheet sheet = workbook.getSheetAt(0);
for (Row row : sheet) {
if (row.getRowNum() == 0) continue; // 跳过表头
Employee emp = new Employee();
emp.setName(row.getCell(0).getStringCellValue());
emp.setAge((int)row.getCell(1).getNumericCellValue());
emp.setDepartment(row.getCell(2).getStringCellValue());
employees.add(emp);
}
}
return employees;
}
6.3 模板导出(基于现有Excel模板)
java
public void exportWithTemplate() throws IOException {
// 加载模板文件
try (InputStream is = new FileInputStream("template.xlsx");
Workbook workbook = new XSSFWorkbook(is)) {
Sheet sheet = workbook.getSheetAt(0);
// 在模板指定位置填充数据
sheet.getRow(5).getCell(3).setCellValue("张三");
sheet.getRow(6).getCell(3).setCellValue(new Date());
// 保存为新文件
try (FileOutputStream fos = new FileOutputStream("output.xlsx")) {
workbook.write(fos);
}
}
}
结语
Apache POI作为Java处理Office文档的事实标准,功能强大但学习曲线适中。本文从最简单的Excel导出开始,逐步深入到大数据处理、图表生成等高级功能,最后介绍了实际项目中的最佳实践。掌握这些技能后,你可以:
- 轻松实现各种报表导出需求
- 处理百万级数据的Excel操作
- 创建专业的数据可视化图表
- 与Web应用无缝集成
建议从简单示例开始实践,逐步挑战更复杂的功能。POI的官方文档(https://poi.apache.org/)是很好的深入学习资源。