赞
踩
EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。
github文档: https://github.com/alibaba/easyexcel
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.3</version>
</dependency>
常用如下两种读取方式
EasyExcel.read(文件名/文件流,数据实体类.class,监听器).sheet().doRead();
EasyExcel.read(文件名/文件流,数据实体类.class,监听器).build();
实例1:
(这里假设已有实体类User)
public void test1() { EasyExcel.read("D:\\file\\1.xlsx", User.class, new AnalysisEventListener<User>() { // 每解析一行数据,该方法会被调用一次 @Override public void invoke(User user, AnalysisContext analysisContext) { System.out.println("解析数据为:" + user.toString()); } // 全部解析完成被调用 @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { System.out.println("解析完成..."); // 保存到数据库 } }).sheet().doRead(); }
实例2:spring项目中导入一个excel文件
(这里假设已有实体类User)
// springboot 接口 @PostMapping("/importUser") public void importUser(@RequestParam("file") MultipartFile file) ExcelReader excelReader = EasyExcel.read(file.getInputStream(), User.class, new AnalysisEventListener<DemoData>() { @Override public void invoke(User user, AnalysisContext analysisContext) { System.out.println("解析数据为:" + user.toString()); } @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { System.out.println("解析完成..."); // 保存到数据库 } }).build(); ReadSheet sheet = EasyExcel.readSheet(0).build(); // 创建sheet对象,读取Excel的第一个sheet, 也可以根据sheet名称获取 excelReader.read(sheet); // 读取sheet表格数据,可以读取多个sheet excelReader.finish(); // 这里必须手动关闭 }
读取多个sheet表格
// 方式1 EasyExcel.read(...) // .sheet(0).doRead(); .doReadAll(); // 读取全部sheet // 方式2 ExcelReader excelReader = EasyExcel.read(...) .build(); ReadSheet sheet = EasyExcel.readSheet(0).build(); //excelReader.read(sheet); excelReader.readAll(); // 读所有sheet excelReader.finish(); // 读指定的多个sheet ExcelReader excelReader = EasyExcel.read(...) .build(); ReadSheet sheet = EasyExcel.readSheet(0).build(); // 读取sheet,有几个就构建几个sheet进行读取 excelReader.read(sheet0); excelReader.finish();
每次调用 EasyExcel.read() 都需要 new 一个 AnalysisEventListener 对象,我们可以将AnalysisEventListener封装为一个对象,方便重复调用
public class EasyExcelUtils<T> { /** * 获取读取Excel的监听器对象 * @param consumer 处理解析数据的函数, 一般可以是数据入库逻辑的函数 * @param threshold 阈值,达到阈值就处理一次存储的数据 * @param <T> 数据模型泛型 * @return 返回监听器 */ public static <T> AnalysisEventListener<T> getReadListener(Consumer<List<T>> consumer, int threshold) { return new AnalysisEventListener<T>() { // ArrayList 查询更快 // List<T> dataList = new ArrayList<>(threshold); // LinkedList 插入和删除更快 List<T> dataList = new LinkedList<>(); /** * 每解析一行调用, 订阅者1 * @param data 解析的每行数据 * @param context */ @Override public void invoke(T data, AnalysisContext context) { dataList.add(data); // 达到阈值就处理一次存储的数据 if (dataList.size() >= threshold) { consumer.accept(dataList); dataList.clear(); } } /** * excel文件解析完成后,事件调度中心会通知到该方法, 订阅者2 * @param context */ @Override public void doAfterAllAnalysed(AnalysisContext context) { // 最后阈值外的数据做处理 if (dataList.size() > 0) { consumer.accept(dataList); } } }; } /** * 获取读取Excel的监听器对象, 不指定阈值, 默认阈值为 2000 */ public static <T> AnalysisEventListener<T> getReadListener(Consumer<List<T>> consumer) { return getReadListener(consumer, 2000); } }
使用示例
// 读取excel文件
public void test() {
EasyExcel.read("user.xlsx", User.class,EasyExcelUtils.getReadListener(dataProcess())).doReadAll();
}
// 处理数据
public Consumer<List<User>> dataProcess() {
return users -> users.forEach(System.out::println);
}
在实体类中加入注解可以格式化数据,
与lombok结合使用。
@NoArgsConstructor @AllArgsConstructor @Data @Builder public class User { @ExcelProperty(value = "字符串标题", index = 0) private String name; @ExcelProperty(value = "日期标题", index = 1) @DateTimeFormat(value = "yyyy年MM月dd日 HH时mm分ss秒") // 格式化日期类型数据 private Date hireDate; @ExcelProperty(value = "数字标题", index = 2) @NumberFormat(value = "###.#") // 格式化数字类型数据,保留一位小数,@NumberFormat不能用在Double类型中 private String salary; }
// 1、根据实体对象导出文件
EasyExcel.write(response.getOutputStream(), 实体.class).sheet().doWrite(list<实体>);
// 2、根据List<List<String>>导出文件
EasyExcel.write(response.getOutputStream()).head(表头list对象).sheet().doWrite(数据list对象);
// 3、根据模板文件
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(new ClassPathResource("模板.xlsx").getInputStream()).build();
WriteSheet writeSheet = EasyExcel.writerSheet().build();
excelWriter.fill(list实体对象, writeSheet); // 填充数据1
excelWriter.fill(map对象, writeSheet); // 填充数据2
excelWriter.finish(); // 关闭流
实例:spring项目中导出excel文件
@PostMapping("/getExcel")
public void getExcel(HttpServletResponse response)
try{
String fileName = "表格文件名.xlsx";
List<数据实体类> data = new ArrayList<>();
fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
EasyExcelFactory.write(response.getOutputStream(), 数据实体类.class)
.sheet("这是一张表名")
.doWrite(data);
response.getOutputStream().flush();
}finally {
response.getOutputStream().close();
}
}
在实体类中定义
@Data
@NoArgsConstructor
//@ContentRowHeight(50)//内容单元格高度
//@HeadRowHeight(50)//表头单元格高度
//@ColumnWidth(50)//单元格宽度
public class User {
@ExcelProperty(value = {"导出台账","序号"})
private Integer no;
@ExcelProperty(value = {"导出台账","编号"})
private String code;
}
EasyExcelFactory.write(...).sheet("表名").registerWriteHandler(new 表头样式对象());
表头样式类型必须继承自CellWriteHandler
public class MyCellWriteHandler implements CellWriteHandler {...}
实体类字段set方法,不能返回this,否者读表格时,无法写入数据到实体类。
也意味着实体类不能添加链式相关注解,例如:lombok的@Accessors(chain = true)
EasyExcel.read(…) 和 EasyExcelFactory.read(…) 有区别吗?
没区别。
下面是EasyExcel的源码
package com.alibaba.excel;
public class EasyExcel extends EasyExcelFactory {
public EasyExcel() {
}
}
你没有看错,EasyExcel.java的源码就这么点
Workbook 是 HSSFWorkbook、XSSFWorkbook的基类
HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls
XSSFWorkbook:是操作Excel2007的版本,扩展名是.xlsx
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。