1. Java操作Excel基础与POI库介绍
在Java生态中,Apache POI是最常用的Excel操作库,它提供了完整的API来读写Microsoft Office格式文件。POI支持两种Excel格式:较老的HSSF(Excel 97-2003,.xls格式)和较新的XSSF(Excel 2007+,.xlsx格式)。对于现代开发,建议优先使用XSSF,因为它支持更大的数据量和更丰富的特性。
要开始使用POI,首先需要在项目中添加依赖。Maven用户可以在pom.xml中添加:
xml复制<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
基础Excel文件创建流程包括:
- 创建工作簿(Workbook)
- 创建工作表(Sheet)
- 创建行(Row)
- 创建单元格(Cell)
- 设置单元格值和样式
- 写入文件
2. 单元格样式深度解析
2.1 字体设置实战
字体是Excel样式中最直观的元素之一。POI中通过XSSFFont类来控制字体属性:
java复制XSSFFont font = workbook.createFont();
font.setFontName("宋体"); // 设置字体
font.setFontHeightInPoints((short)12); // 字号
font.setBold(true); // 加粗
font.setItalic(true); // 斜体
font.setUnderline(FontUnderline.SINGLE); // 下划线
font.setColor(IndexedColors.RED.getIndex()); // 字体颜色
// 应用到样式
XSSFCellStyle style = workbook.createCellStyle();
style.setFont(font);
注意:中文字体名称要确保在系统中存在,否则会回退到默认字体。常见的稳妥选择包括"宋体"、"黑体"、"微软雅黑"等。
2.2 边框设置技巧
边框设置是报表美观的关键。POI提供了细粒度控制:
java复制XSSFCellStyle style = workbook.createCellStyle();
style.setBorderTop(BorderStyle.THIN); // 上边框
style.setBorderBottom(BorderStyle.DOUBLE); // 下边框
style.setBorderLeft(BorderStyle.MEDIUM); // 左边框
style.setBorderRight(BorderStyle.DASHED); // 右边框
// 设置边框颜色
style.setTopBorderColor(IndexedColors.BLUE.getIndex());
style.setBottomBorderColor(IndexedColors.RED.getIndex());
边框样式可选值:
BorderStyle.NONE:无边框BorderStyle.THIN:细线BorderStyle.MEDIUM:中等BorderStyle.DASHED:虚线BorderStyle.DOUBLE:双线
2.3 背景色与填充模式
背景设置需要同时指定颜色和填充模式:
java复制XSSFCellStyle style = workbook.createCellStyle();
style.setFillForegroundColor(new XSSFColor(new byte[]{(byte)220, (byte)220, (byte)220}, null)); // RGB灰色
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
重要提示:必须同时设置FillPatternType,否则背景色不会生效。SOLID_FOREGROUND表示纯色填充。
3. 单元格尺寸精确控制
3.1 列宽设置原理
Excel中列宽的单位比较特殊,1个字符宽度≈256个内部单位。POI提供了两种设置方式:
java复制sheet.setColumnWidth(columnIndex, widthInUnits); // 精确值
sheet.autoSizeColumn(columnIndex); // 自动调整
经验值参考:
- 中文通常需要设置更大的宽度
- 日期格式建议宽度≥3000
- 数字列建议宽度≥2000
3.2 行高最佳实践
行高以"点"为单位(1点=1/72英寸):
java复制row.setHeightInPoints(20); // 20点高
自动换行时需要增加行高:
java复制style.setWrapText(true); // 启用自动换行
// 通常需要随后调用autoSizeColumn()
4. 对齐与文本控制
4.1 水平与垂直对齐
java复制style.setAlignment(HorizontalAlignment.CENTER); // 水平居中
style.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中
对齐方式可选值:
- 水平:LEFT, CENTER, RIGHT, FILL, JUSTIFY
- 垂直:TOP, CENTER, BOTTOM, JUSTIFY
4.2 文本旋转与缩进
java复制style.setRotation((short)90); // 90度旋转
style.setIndention((short)2); // 缩进2字符
5. 高级样式技巧
5.1 样式复用与缓存
创建样式是相对耗时的操作,应该尽量复用:
java复制// 创建样式缓存
Map<String, XSSFCellStyle> styleCache = new HashMap<>();
XSSFCellStyle getOrCreateStyle(String key) {
if(!styleCache.containsKey(key)) {
XSSFCellStyle style = workbook.createCellStyle();
// 配置样式...
styleCache.put(key, style);
}
return styleCache.get(key);
}
5.2 条件格式设置
POI支持条件格式,可以创建类似热力图的效果:
java复制SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
ConditionalFormattingRule rule = sheetCF.createConditionalFormattingRule(
ComparisonOperator.BETWEEN,
"10", "20"
);
PatternFormatting fill = rule.createPatternFormatting();
fill.setFillBackgroundColor(IndexedColors.YELLOW.index);
fill.setFillPattern(PatternFormatting.SOLID_FOREGROUND);
CellRangeAddress[] regions = {
CellRangeAddress.valueOf("A1:C10")
};
sheetCF.addConditionalFormatting(regions, rule);
6. 性能优化与常见问题
6.1 内存管理
处理大文件时需要注意内存使用:
- 使用SXSSFWorkbook处理大数据(基于XSSF的流式API)
- 及时关闭资源:
java复制try (Workbook workbook = new XSSFWorkbook();
OutputStream out = new FileOutputStream("report.xlsx")) {
// 操作workbook
workbook.write(out);
}
6.2 常见问题排查
-
样式不生效:
- 确保没有在其他地方覆盖了样式
- 检查是否漏掉了必要的设置(如FillPattern)
-
中文乱码:
- 确保使用支持中文的字体
- 检查文件编码(推荐UTF-8)
-
自动调整列宽不准确:
- 中文需要额外宽度
- 可能需要手动调用autoSizeColumn()多次
-
文件损坏:
- 确保正确关闭了所有流
- 检查POI版本兼容性
7. 完整示例代码
java复制public class ExcelGenerator {
public static void generateStyledExcel(String filePath) throws IOException {
try (XSSFWorkbook workbook = new XSSFWorkbook()) {
XSSFSheet sheet = workbook.createSheet("样式演示");
// 创建标题行样式
XSSFCellStyle headerStyle = workbook.createCellStyle();
XSSFFont headerFont = workbook.createFont();
headerFont.setBold(true);
headerFont.setFontHeightInPoints((short)14);
headerFont.setColor(IndexedColors.WHITE.getIndex());
headerStyle.setFont(headerFont);
headerStyle.setFillForegroundColor(new XSSFColor(new byte[]{(byte)79, (byte)129, (byte)189}, null));
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
headerStyle.setAlignment(HorizontalAlignment.CENTER);
headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
headerStyle.setBorderBottom(BorderStyle.MEDIUM);
// 创建数据行样式
XSSFCellStyle dataStyle = workbook.createCellStyle();
dataStyle.setBorderBottom(BorderStyle.THIN);
dataStyle.setBorderLeft(BorderStyle.THIN);
dataStyle.setBorderRight(BorderStyle.THIN);
dataStyle.setBorderTop(BorderStyle.THIN);
dataStyle.setAlignment(HorizontalAlignment.RIGHT);
// 创建标题行
Row headerRow = sheet.createRow(0);
String[] headers = {"日期", "销售额", "利润率"};
for (int i = 0; i < headers.length; i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(headers[i]);
cell.setCellStyle(headerStyle);
sheet.setColumnWidth(i, 4000);
}
// 填充数据
Random random = new Random();
for (int i = 1; i <= 10; i++) {
Row row = sheet.createRow(i);
row.setHeightInPoints(20);
// 日期列
Cell dateCell = row.createCell(0);
dateCell.setCellValue(LocalDate.now().minusDays(10 - i).toString());
// 销售额列
Cell salesCell = row.createCell(1);
double sales = 10000 + random.nextDouble() * 5000;
salesCell.setCellValue(sales);
// 利润率列
Cell profitCell = row.createCell(2);
double profit = 0.1 + random.nextDouble() * 0.1;
profitCell.setCellValue(profit);
// 应用样式
for (int j = 0; j < headers.length; j++) {
row.getCell(j).setCellStyle(dataStyle);
}
}
// 写入文件
try (OutputStream out = new FileOutputStream(filePath)) {
workbook.write(out);
}
}
}
}
在实际项目中,我通常会将这些样式配置封装成工具类,通过Builder模式来构建不同的样式组合。对于复杂的报表,建议使用模板方式(先创建好带样式的Excel模板,然后通过POI填充数据),这样既能保证样式统一,又能提高生成效率。
