HSSFWorkbook (xls) / SXSSFWorkbook (大数据流式)。<T> + 反射,自动映射实体属性到列。yyyy-MM-dd HH:mm:ss。List headersParams 格式 "表头=属性名"。<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version> <!-- 或 4.x/5.x -->
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>
public class NextExcelUtil {
// 常量
private static final int MAX_MSG_BODY_SIZE = 1020; // 示例常量,实际工具类中无此常量
/** 单 Sheet 导出入口 */
public static Workbook getWorkbook(String title, List headersParams, List dataList) { ... }
/** 多 Sheet 分页导出入口 */
public static Workbook getWorkbook(String title, List headersParams, List dataList, int sheetMaxCount) { ... }
// 内部:拆分大 List
private static List> getSplitList(List dataList, int sheetMaxCount) { ... }
// 内部:反射获取 getter 方法名
private static String getMethodName(String fieldName) {
return "get" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
}
// 内部:单元格样式构建(标题、表头、数据行)
private static CellStyle getStyle(Workbook wb) { ... }
private static CellStyle getTitleStyle(Workbook wb) { ... }
private static CellStyle getColumnTopStyle(Workbook wb) { ... }
private static CellStyle getCellStyle(Workbook wb) { ... }
}
int page = (count % sheetMaxCount > 0) ? count/sheetMaxCount + 1 : count/sheetMaxCount;
List> splitList = getSplitList(dataList, sheetMaxCount);
for (int i = 0; i < page; i++) {
Sheet sheet = wb.createSheet();
if (title != null) wb.setSheetName(i, title + (i+1));
// ... 写标题、表头、数据 ...
}
// 占用前两行
for (int j = 0; j < 2; j++) {
Row titleRow = sheet.createRow(j);
for (int k = 0; k < headersParams.size(); k++) {
Cell cell = titleRow.createCell(k);
cell.setCellStyle(titleStyle);
if (j == 0 && k == 0) cell.setCellValue(title); // 仅左上角写值
}
}
// 合并区域:起始行0,终止行1,起始列0,终止列最后一列
sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, headersParams.size()-1));
Class> clazz = dataList.get(0).getClass();
for (int i = 0; i < dataList.size(); i++) {
Row row = sheet.createRow(i + 1 + headerOffset);
for (int j = 0; j < params.length; j++) {
Field field = clazz.getDeclaredField(params[j]);
Method method = clazz.getMethod(getMethodName(params[j]));
Object val = method.invoke(dataList.get(i));
Cell cell = row.createCell(j);
// 日期特殊处理
if (val instanceof Date) {
CellStyle dateStyle = wb.createCellStyle();
dateStyle.setDataFormat(wb.getCreationHelper().createDataFormat().getFormat("yyyy-MM-dd HH:mm:ss"));
cell.setCellStyle(dateStyle);
cell.setCellValue((Date) val);
} else {
cell.setCellValue(val != null ? val.toString() : "");
}
}
}
统一定义边框、居中、字体加粗等 CellStyle,避免重复创建导致样式数量超限(HSSF 限制 4000 个)。
List users = userService.findAll();
List headers = Arrays.asList("姓名=name", "年龄=age", "注册时间=createTime");
Workbook wb = NextExcelUtil.getWorkbook("用户导出", headers, users, 50000); // 每 Sheet 5万行
try (FileOutputStream fos = new FileOutputStream("users.xls")) {
wb.write(fos);
}
SXSSFWorkbook (POI 3.8+),内存占用极低。wb.close() 释放临时文件(SXSSF)。Style records exceed 4000 错误。