Apache POI Excel 导出样式美化实战指南

📅 2026/6/24 9:06:37
Apache POI Excel 导出样式美化实战指南
Apache POI Excel 导出样式美化实战指南一、概述使用 Apache POI 导出 Excel 时默认样式非常简陋无边框、无背景色、列宽不自适应。在实际项目中导出给用户的 Excel 文件需要具备良好的可读性包括表头美化、数据对齐、边框、列宽自适应等。本文以XSSFWorkbook.xlsx 格式为例系统介绍 POI 中样式相关 API 的使用方法。二、POI 样式体系结构Workbook工作簿 ├── Font字体— 控制文字样式 ├── CellStyle单元格样式— 控制单元格外观 ├── Sheet工作表 │ ├── Row行— 控制行高 │ │ └── Cell单元格— 绑定 CellStyle │ └── 列宽设置关键关系Font被CellStyle引用CellStyle被Cell引用一个CellStyle可以被多个Cell共用推荐复用减少内存开销注博客https://blog.csdn.net/badao_liumang_qizhi三、核心 API 详解3.1 字体FontFontfontworkbook.createFont();font.setBold(true);// 加粗font.setItalic(true);// 斜体font.setFontHeightInPoints((short)12);// 字号磅font.setFontName(微软雅黑);// 字体名称font.setColor(IndexedColors.WHITE.getIndex());// 字体颜色font.setUnderline(Font.U_SINGLE);// 下划线font.setStrikeout(true);// 删除线3.2 单元格样式CellStyle背景填充CellStylestyleworkbook.createCellStyle();// 设置背景色必须先设置前景色再设置填充模式style.setFillForegroundColor(IndexedColors.ROYAL_BLUE.getIndex());style.setFillPattern(FillPatternType.SOLID_FOREGROUND);常用颜色颜色常量效果IndexedColors.ROYAL_BLUE深蓝色适合表头IndexedColors.LIGHT_BLUE浅蓝色IndexedColors.GREY_25_PERCENT浅灰色适合交替行IndexedColors.LIGHT_YELLOW浅黄色IndexedColors.WHITE白色IndexedColors.RED红色适合错误标记对齐方式// 水平对齐style.setAlignment(HorizontalAlignment.CENTER);// 居中style.setAlignment(HorizontalAlignment.LEFT);// 左对齐style.setAlignment(HorizontalAlignment.RIGHT);// 右对齐// 垂直对齐style.setVerticalAlignment(VerticalAlignment.CENTER);// 垂直居中style.setVerticalAlignment(VerticalAlignment.TOP);// 顶部对齐style.setVerticalAlignment(VerticalAlignment.BOTTOM);// 底部对齐边框// 四边边框细线style.setBorderTop(BorderStyle.THIN);style.setBorderBottom(BorderStyle.THIN);style.setBorderLeft(BorderStyle.THIN);style.setBorderRight(BorderStyle.THIN);// 边框颜色可选默认黑色style.setTopBorderColor(IndexedColors.BLACK.getIndex());style.setBottomBorderColor(IndexedColors.BLACK.getIndex());style.setLeftBorderColor(IndexedColors.BLACK.getIndex());style.setRightBorderColor(IndexedColors.BLACK.getIndex());边框样式常量效果BorderStyle.THIN细线最常用BorderStyle.MEDIUM中等粗线BorderStyle.THICK粗线BorderStyle.DASHED虚线BorderStyle.DOTTED点线BorderStyle.NONE无边框自动换行style.setWrapText(true);// 内容超出列宽时自动换行绑定字体style.setFont(font);// 将 Font 对象绑定到 CellStyle3.3 行高Rowrowsheet.createRow(0);row.setHeightInPoints(20);// 行高20磅// 或row.setHeight((short)(20*20));// 单位是 1/20 磅3.4 列宽// 固定列宽单位是 1/256 个字符宽度sheet.setColumnWidth(0,5000);// 第0列宽度约20个字符// 自适应列宽根据内容自动调整sheet.autoSizeColumn(0);// 自适应 额外余量推荐sheet.autoSizeColumn(0);intwidthsheet.getColumnWidth(0);sheet.setColumnWidth(0,Math.max(width512,4000));// 至少4000宽度注意autoSizeColumn对中文支持不够好可能偏窄建议加 512~1024 的余量。四、完整示例publicStringexportEmployee(ListEmployeeExportDtodataList){XSSFWorkbookworkbooknewXSSFWorkbook();Sheetsheetworkbook.createSheet(员工信息);// 1. 定义表头样式 FontheaderFontworkbook.createFont();headerFont.setBold(true);headerFont.setColor(IndexedColors.WHITE.getIndex());headerFont.setFontHeightInPoints((short)11);headerFont.setFontName(微软雅黑);CellStyleheaderStyleworkbook.createCellStyle();headerStyle.setFont(headerFont);headerStyle.setFillForegroundColor(IndexedColors.ROYAL_BLUE.getIndex());headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);headerStyle.setAlignment(HorizontalAlignment.CENTER);headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);headerStyle.setBorderTop(BorderStyle.THIN);headerStyle.setBorderBottom(BorderStyle.THIN);headerStyle.setBorderLeft(BorderStyle.THIN);headerStyle.setBorderRight(BorderStyle.THIN);// 2. 定义数据行样式 FontdataFontworkbook.createFont();dataFont.setFontHeightInPoints((short)10);dataFont.setFontName(微软雅黑);CellStyledataStyleworkbook.createCellStyle();dataStyle.setFont(dataFont);dataStyle.setAlignment(HorizontalAlignment.LEFT);dataStyle.setVerticalAlignment(VerticalAlignment.CENTER);dataStyle.setWrapText(true);dataStyle.setBorderTop(BorderStyle.THIN);dataStyle.setBorderBottom(BorderStyle.THIN);dataStyle.setBorderLeft(BorderStyle.THIN);dataStyle.setBorderRight(BorderStyle.THIN);// 3. 创建表头行 String[]headers{工号,姓名,部门,手机号,状态,操作人,创建时间};RowheaderRowsheet.createRow(0);headerRow.setHeightInPoints(22);for(inti0;iheaders.length;i){CellcellheaderRow.createCell(i);cell.setCellValue(headers[i]);cell.setCellStyle(headerStyle);}// 4. 填充数据行 SimpleDateFormatsdfnewSimpleDateFormat(yyyy-MM-dd HH:mm:ss);for(inti0;idataList.size();i){EmployeeExportDtodtodataList.get(i);Rowrowsheet.createRow(i1);row.setHeightInPoints(18);createStyledCell(row,0,dto.getStaffNo(),dataStyle);createStyledCell(row,1,dto.getStaffName(),dataStyle);createStyledCell(row,2,dto.getDeptName(),dataStyle);createStyledCell(row,3,dto.getPhone(),dataStyle);createStyledCell(row,4,dto.getStatusName(),dataStyle);createStyledCell(row,5,dto.getOperatorName(),dataStyle);createStyledCell(row,6,dto.getCreateTime()!null?sdf.format(dto.getCreateTime()):,dataStyle);}// 5. 设置列宽自适应 for(inti0;iheaders.length;i){sheet.autoSizeColumn(i);intcurrentWidthsheet.getColumnWidth(i);sheet.setColumnWidth(i,Math.max(currentWidth512,4000));}// 6. 写入文件并上传 // ...省略文件操作代码returnossUrl;}/** * 创建带样式的单元格. */privatevoidcreateStyledCell(Rowrow,intcolIndex,Stringvalue,CellStylestyle){Cellcellrow.createCell(colIndex);cell.setCellValue(value!null?value:);cell.setCellStyle(style);}五、样式复用原则5.1 为什么要复用 CellStylePOI 中每个 Workbook 最多支持约 64000 个 CellStyle。如果每个 Cell 都 new 一个 CellStyle数据量大时会报错java.lang.IllegalStateException: The maximum number of Cell Styles was exceeded.5.2 正确做法// 正确在循环外创建样式循环内复用CellStyledataStyleworkbook.createCellStyle();// ... 设置样式属性for(inti0;idataList.size();i){Rowrowsheet.createRow(i1);Cellcellrow.createCell(0);cell.setCellStyle(dataStyle);// 复用同一个样式对象}// 错误在循环内创建样式for(inti0;idataList.size();i){CellStylestyleworkbook.createCellStyle();// 每行创建新样式浪费资源// ...}5.3 需要多种样式时如果需要交替行背景色等不同样式预先创建有限个样式对象// 创建两种数据行样式白色背景 浅灰背景CellStyleevenStylecreateDataStyle(workbook,IndexedColors.WHITE);CellStyleoddStylecreateDataStyle(workbook,IndexedColors.GREY_25_PERCENT);for(inti0;idataList.size();i){CellStylestyle(i%20)?evenStyle:oddStyle;// 使用对应样式}六、常见样式模板6.1 标准表头蓝底白字FontheaderFontworkbook.createFont();headerFont.setBold(true);headerFont.setColor(IndexedColors.WHITE.getIndex());headerFont.setFontHeightInPoints((short)11);CellStyleheaderStyleworkbook.createCellStyle();headerStyle.setFont(headerFont);headerStyle.setFillForegroundColor(IndexedColors.ROYAL_BLUE.getIndex());headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);headerStyle.setAlignment(HorizontalAlignment.CENTER);headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);headerStyle.setBorderTop(BorderStyle.THIN);headerStyle.setBorderBottom(BorderStyle.THIN);headerStyle.setBorderLeft(BorderStyle.THIN);headerStyle.setBorderRight(BorderStyle.THIN);6.2 标准数据行左对齐换行边框FontdataFontworkbook.createFont();dataFont.setFontHeightInPoints((short)10);CellStyledataStyleworkbook.createCellStyle();dataStyle.setFont(dataFont);dataStyle.setAlignment(HorizontalAlignment.LEFT);dataStyle.setVerticalAlignment(VerticalAlignment.CENTER);dataStyle.setWrapText(true);dataStyle.setBorderTop(BorderStyle.THIN);dataStyle.setBorderBottom(BorderStyle.THIN);dataStyle.setBorderLeft(BorderStyle.THIN);dataStyle.setBorderRight(BorderStyle.THIN);6.3 数字列右对齐CellStylenumberStyleworkbook.createCellStyle();numberStyle.cloneStyleFrom(dataStyle);// 基于数据行样式克隆numberStyle.setAlignment(HorizontalAlignment.RIGHT);// 可选设置数字格式DataFormatformatworkbook.createDataFormat();numberStyle.setDataFormat(format.getFormat(#,##0.00));6.4 错误标记行红色字体FonterrorFontworkbook.createFont();errorFont.setColor(IndexedColors.RED.getIndex());errorFont.setFontHeightInPoints((short)10);CellStyleerrorStyleworkbook.createCellStyle();errorStyle.setFont(errorFont);errorStyle.setAlignment(HorizontalAlignment.LEFT);errorStyle.setBorderTop(BorderStyle.THIN);errorStyle.setBorderBottom(BorderStyle.THIN);errorStyle.setBorderLeft(BorderStyle.THIN);errorStyle.setBorderRight(BorderStyle.THIN);七、列宽自适应的坑7.1 中文字符宽度不准autoSizeColumn对中文计算宽度偏窄因为 POI 默认按英文字符宽度计算。解决自适应后加余量sheet.autoSizeColumn(i);intwidthsheet.getColumnWidth(i);sheet.setColumnWidth(i,(int)(width*1.2));// 增加20%7.2 大数据量性能问题autoSizeColumn需要遍历该列所有行来计算最大宽度数据量大时很慢。解决数据量 1万行时改用固定列宽if(dataList.size()10000){// 固定列宽int[]columnWidths{4000,5000,6000,5000,4000,5000,6000};for(inti0;icolumnWidths.length;i){sheet.setColumnWidth(i,columnWidths[i]);}}else{// 自适应for(inti0;iheaders.length;i){sheet.autoSizeColumn(i);sheet.setColumnWidth(i,Math.max(sheet.getColumnWidth(i)512,4000));}}八、最佳实践清单样式对象在循环外创建避免超出 64000 个 CellStyle 限制表头和数据行使用不同样式表头加粗背景色数据行左对齐换行所有单元格设置边框提升可读性表头行高适当加大建议 20-22pt数据行开启自动换行防止长文本被截断列宽自适应后加余量中文内容需要额外 512-1024 的宽度null 值转空字符串避免 Cell 显示 “null”封装 createStyledCell 方法减少重复代码数字列右对齐符合阅读习惯大数据量用固定列宽autoSizeColumn 性能差