本文目录导读:

下面我为你详细介绍 EasyExcel 的使用方法,这是阿里开源的一个非常好用的 Java Excel 工具库,特别适合处理大数据量、内存占用低的场景。
EasyExcel 简介
核心优势:
- 内存占用极低(相比 POI,能节省 90% 以上)
- 使用简单,API 友好
- 支持大数据量的读写(百万级)
- 支持模板填充
Maven 依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.2</version>
</dependency>
注意:如果你的项目中使用 Lombok,建议搭配使用,可以少写很多 Getter/Setter 代码。
快速入门:写 Excel
最简单的写操作
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
// 1. 先定义数据模型
@Data
public class UserData {
@ExcelProperty("用户ID")
private Long userId;
@ExcelProperty("用户名")
private String userName;
@ExcelProperty("年龄")
private Integer age;
@ExcelProperty("邮箱")
private String email;
}
// 2. 写入数据
public class WriteTest {
public static void main(String[] args) {
// 准备数据
List<UserData> userList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
UserData user = new UserData();
user.setUserId((long) i);
user.setUserName("用户" + i);
user.setAge(20 + i);
user.setEmail("user" + i + "@example.com");
userList.add(user);
}
// 写入 Excel
String fileName = "用户数据.xlsx";
EasyExcel.write(fileName, UserData.class)
.sheet("用户信息")
.doWrite(userList);
System.out.println("写入成功!");
}
}
自定义样式和格式
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
public class WriteWithStyle {
public static void main(String[] args) {
// 设置表头样式
WriteCellStyle headStyle = new WriteCellStyle();
WriteFont headFont = new WriteFont();
headFont.setBold(true);
headFont.setFontHeightInPoints((short) 12);
headFont.setColor(IndexedColors.WHITE.getIndex());
headStyle.setWriteFont(headFont);
headStyle.setFillForegroundColor(IndexedColors.BLUE.getIndex());
// 设置内容样式
WriteCellStyle contentStyle = new WriteCellStyle();
WriteFont contentFont = new WriteFont();
contentFont.setFontHeightInPoints((short) 10);
contentStyle.setWriteFont(contentFont);
// 组合策略
HorizontalCellStyleStrategy strategy = new HorizontalCellStyleStrategy(headStyle, contentStyle);
String fileName = "带样式的用户数据.xlsx";
EasyExcel.write(fileName, UserData.class)
.registerWriteHandler(strategy)
.sheet("用户信息")
.doWrite(getUserList());
}
}
读 Excel
同步读取(适合小文件)
import com.alibaba.excel.EasyExcel;
public class SimpleRead {
public static void main(String[] args) {
String fileName = "用户数据.xlsx";
// 同步读取,直接返回 List
List<UserData> list = EasyExcel.read(fileName)
.head(UserData.class)
.sheet()
.doReadSync();
// 打印读取到的数据
list.forEach(System.out::println);
}
}
异步读取(推荐,适合大数据量)
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
public class AsyncRead {
public static void main(String[] args) {
String fileName = "用户数据.xlsx";
EasyExcel.read(fileName, UserData.class, new ReadListener<UserData>() {
// 每读取一行,调用一次
@Override
public void invoke(UserData data, AnalysisContext context) {
System.out.println("读取到数据:" + data);
}
// 所有数据读取完成后的操作
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println("所有数据读取完成!");
}
}).sheet().doRead();
}
}
批量处理读取(推荐方式)
public class BatchRead {
// 每批处理的条数
private static final int BATCH_COUNT = 100;
public static void main(String[] args) {
String fileName = "用户数据.xlsx";
EasyExcel.read(fileName, UserData.class, new ReadListener<UserData>() {
private List<UserData> batchList = new ArrayList<>(BATCH_COUNT);
@Override
public void invoke(UserData data, AnalysisContext context) {
batchList.add(data);
// 达到 BATCH_COUNT 时,批量处理
if (batchList.size() >= BATCH_COUNT) {
processBatch();
batchList.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 处理剩余数据
if (!batchList.isEmpty()) {
processBatch();
}
System.out.println("所有数据处理完成!");
}
private void processBatch() {
// 批量处理数据,比如批量插入数据库
System.out.println("批量处理 " + batchList.size() + " 条数据");
}
}).sheet().doRead();
}
}
高级用法
动态头(表头不固定时)
public class DynamicHeadWrite {
public static void main(String[] args) {
// 动态构建表头
List<List<String>> head = new ArrayList<>();
head.add(Arrays.asList("姓名", "基本信息")); // 合并单元格
head.add(Arrays.asList("年龄", "基本信息"));
head.add(Arrays.asList("邮箱", "联系方式"));
head.add(Arrays.asList("电话", "联系方式"));
// 准备数据
List<List<String>> data = new ArrayList<>();
data.add(Arrays.asList("张三", "25", "zhangsan@example.com", "13800138000"));
data.add(Arrays.asList("李四", "30", "lisi@example.com", "13900139000"));
String fileName = "动态表头.xlsx";
EasyExcel.write(fileName)
.head(head)
.sheet("数据")
.doWrite(data);
}
}
模板填充
public class TemplateFill {
public static void main(String[] args) {
String templateFile = "模板.xlsx";
String outputFile = "填充结果.xlsx";
// 准备填充数据
Map<String, Object> fillData = new HashMap<>();
fillData.put("name", "张三");
fillData.put("age", 25);
fillData.put("createDate", new Date());
// 填充单个对象
EasyExcel.write(outputFile)
.withTemplate(templateFile)
.sheet()
.doFill(fillData);
}
}
数据验证
public class DataValidation {
// 使用 @ExcelProperty 注解进行简单验证
@Data
public static class ValidatedData {
@ExcelProperty("必填字段")
@NotBlank(message = "不能为空")
private String requiredField;
@ExcelProperty("数字字段")
@Min(value = 0, message = "不能小于0")
@Max(value = 100, message = "不能大于100")
private Integer numberField;
@ExcelProperty("长度限制")
@Size(max = 10, message = "长度不能超过10")
private String limitedField;
}
}
性能优化建议
大数据量写入
public class LargeDataWrite {
public static void main(String[] args) {
String fileName = "大数据.xlsx";
EasyExcel.write(fileName, UserData.class)
.sheet("数据")
.doWrite(() -> {
// 数据分批获取,避免一次性加载到内存
for (int i = 0; i < 10000; i++) {
List<UserData> batch = getBatchData(i);
return batch;
}
return null;
});
}
}
内存优化配置
public class MemoryOptimized {
public static void main(String[] args) {
// 写入优化
EasyExcel.write(fileName, UserData.class)
.inMemory(false) // 使用文件缓存,减少内存使用
.sheet("数据")
.doWrite(dataList);
// 读取优化
EasyExcel.read(fileName, UserData.class, new ReadListener<UserData>() {
@Override
public void invoke(UserData data, AnalysisContext context) {
// 逐行处理,不加载全部到内存
processLine(data);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 完成
}
})
.sheet()
.doRead();
}
}
常见问题解决
日期格式处理
@Data
public class DateDemo {
@ExcelProperty("日期")
@DateTimeFormat("yyyy年MM月dd日")
private Date date;
@ExcelProperty("时间")
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;
}
数字格式化
@Data
public class NumberDemo {
@ExcelProperty("金额")
@NumberFormat("#.##")
private Double money;
@ExcelProperty("百分比")
@NumberFormat("#%")
private Double percentage;
}
导入时忽略某些列
@Data
public class IgnoreColumnDemo {
@ExcelProperty("姓名")
private String name;
@ExcelProperty("年龄")
private Integer age;
@ExcelIgnore // 忽略这个字段
private String ignoreField;
@ExcelProperty(index = 3) // 指定列索引
private String otherField;
}
选择 EasyExcel 的场景:
- 需要处理大数据量 Excel(万级以上)
- 内存敏感的应用
- 需要高性能的 Excel 读写
- 想要简单易用的 API
注意事项:
- 尽量使用异步读取,避免 OOM
- 大数据量写入时,使用分批写入
- 注意文件路径和流资源的正确关闭
- 测试环境验证后再应用于生产
希望这个指南能帮助你快速上手 EasyExcel!如果你有具体的业务场景,可以告诉我,我可以提供更针对性的示例。