EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽量节约内存的状况下支持读写百M的Excel。相对于Apache POI来讲,EasyExcel是从磁盘上一行行的读取数据,而后逐个解析,避免将大量数据加载到内存从而致使OOM。java
相关依赖:web
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.6</version> </dependency> <!-- 可选 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>provided</scope> </dependency>
须要导入的数据:
spring
Model类:app
@Data public class SchoolData { @ExcelProperty(value = "地址") private String address; @ExcelProperty(value = "学校名称") private String schoolName; @ExcelProperty(value = "邮政编码") private String postcode; @ExcelProperty(value = "收集时间") private Date collectDate; }
使用@ExcelProperty注解时,可使用两种方式将数据列和属性进行绑定:ide
在不使用@ExcelProperty注解时,默认Model类属性和excel列数据按照前后顺序进行绑定的。post
监听器:测试
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import java.util.ArrayList; import java.util.List; import java.util.Map; public class SchoolDataListener extends AnalysisEventListener<SchoolData> { List<SchoolData> schoolDataList = new ArrayList<>(); //须要传参时,经过构造方法传进来 public SchoolDataListener() { } /** * 每解析一行数据都会进行调用 */ @Override public void invoke(SchoolData data, AnalysisContext context) { //通常数据量大的时候应该分批处理,防止数据所有加载到内存,致使OOM。 schoolDataList.add(data); } /** * 数据所有解析完成时调用 */ @Override public void doAfterAllAnalysed(AnalysisContext context) { System.out.println("数据读取完毕:"); schoolDataList.stream().forEach(System.out::println); } /** * 每解析一行表头都会进行调用 */ @Override public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) { System.out.println("表头:"); headMap.forEach((k, v) -> System.out.println(v)); System.out.println(); } }
导入测试:ui
导入有如下两种写法,通常使用简写的方式就行,当须要实现复杂的功能时可能会须要另一种复杂的写法。编码
@Test public void importExcel() { ExcelReader excelReader = null; try { excelReader = EasyExcel.read("F:\\测试数据.xlsx", SchoolData.class, new SchoolDataListener()).build(); ReadSheet readSheet = EasyExcel.readSheet(0).build(); excelReader.read(readSheet); } finally { if (excelReader != null) { // 这里千万别忘记关闭,读的时候会建立临时文件,到时磁盘会崩的 excelReader.finish(); } } } @Test public void importExcelSimple() { //sheet() 默认读取第一个sheet EasyExcel.read("F:\\测试数据.xlsx", SchoolData.class, new SchoolDataListener()).sheet().doRead(); }
输出结果:.net
表头: 学校名称 地址 邮政编码 收集时间 数据读取完毕: SchoolData(address=晋宁县古城镇旧寨村 , schoolName=晋宁县古城镇古城中学, postcode=650604, collectDate=Sun Jan 05 00:00:00 CST 2020) SchoolData(address=云南省昆明市晋宁县二街乡老高村 , schoolName=晋宁县二街中学, postcode=650608, collectDate=Mon Jan 06 00:00:00 CST 2020) SchoolData(address=云南省昆明市晋宁县晋城镇寺林街 , schoolName=晋宁县晋城中学, postcode=650605, collectDate=Tue Jan 07 00:00:00 CST 2020) SchoolData(address=云南省晋宁县六街乡中学 , schoolName=晋宁县六街中学, postcode=650609, collectDate=Wed Jan 08 00:00:00 CST 2020) SchoolData(address=云南省昆明市晋宁县新街乡文河村 , schoolName=晋宁县新街中学, postcode=650606, collectDate=Thu Jan 09 00:00:00 CST 2020) SchoolData(address=晋宁县中和乡普照路 , schoolName=晋宁县中和中学, postcode=650600, collectDate=Fri Jan 10 00:00:00 CST 2020) SchoolData(address=云南省昆明市晋宁县上蒜乡上蒜中学 , schoolName=晋宁县上蒜乡上蒜中学, postcode=650607, collectDate=Sat Jan 11 00:00:00 CST 2020) SchoolData(address=云南省昆明市晋宁县化乐乡化乐村 , schoolName=晋宁县化乐乡中学, postcode=650611, collectDate=Sun Jan 12 00:00:00 CST 2020) SchoolData(address=晋宁县夕阳乡夕阳街夕阳民族中学 , schoolName=晋宁县夕阳民族中学, postcode=650603, collectDate=Mon Jan 13 00:00:00 CST 2020) SchoolData(address=云南省昆明市晋宁县宝峰镇古城村委会小古城村 , schoolName=晋宁县宝峰镇宝峰中学, postcode=650601, collectDate=Tue Jan 14 00:00:00 CST 2020) SchoolData(address=晋宁县双河乡椿树营 , schoolName=晋宁县双河民族中学, postcode=650602, collectDate=Wed Jan 15 00:00:00 CST 2020) SchoolData(address=昆明市富民县永定镇环城南路7号永定中学 , schoolName=富民县永定中学, postcode=650400, collectDate=Thu Jan 16 00:00:00 CST 2020) SchoolData(address=富民县永定镇大西山村 , schoolName=富民县勤劳中学, postcode=650400, collectDate=Fri Jan 17 00:00:00 CST 2020) SchoolData(address=富民县大营镇大营街16号 , schoolName=富民县大营中学, postcode=650400, collectDate=Sat Jan 18 00:00:00 CST 2020) SchoolData(address=云南省昆明市罗免乡者北村委会者北街 , schoolName=富民县第二中学, postcode=650401, collectDate=Sun Jan 19 00:00:00 CST 2020)
模拟生成数据:
public class DataGenerate { /** * 数据生成 */ public static List<SchoolData> data() { List<SchoolData> schoolDataList = new ArrayList<>(); SchoolData schoolData; for (int i = 0; i < 15; i++) { schoolData = new SchoolData(); schoolData.setSchoolName("第" + i + "XXX中学"); schoolData.setAddress("云南省昆明市XXXXX"); schoolData.setPostcode("123456"); schoolData.setCollectDate(new Date()); schoolDataList.add(schoolData); } return schoolDataList; } }
测试导出:
同导入,导出也有如下两种写法。LongestMatchColumnWidthStyleStrategy用来设置自动列宽,若是须要设置列宽、行高等属性,能够在Model类上添加对应注解进行设置,如@ColumnWidth、@ContentRowHeight、@HeadRowHeight等等。
@Test public void exportExcel() { ExcelWriter excelWriter = null; try { excelWriter = EasyExcel.write("F:\\测试数据_副本.xlsx", SchoolData.class).build(); WriteSheet writeSheet = EasyExcel.writerSheet("学校数据").registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build(); excelWriter.write(DataGenerate.data(), writeSheet); } finally { // 千万别忘记finish 会帮忙关闭流 if (excelWriter != null) { excelWriter.finish(); } } } @Test public void exportExcelSimple() { EasyExcel.write("F:\\测试数据_副本.xlsx", SchoolData.class).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("学校数据").doWrite(DataGenerate.data()); }
导出结果:
模板:
{} 表明普通变量 {.} 表明是list的变量。
模板填充测试:
@Test public void excelTemplateFill() { ExcelWriter excelWriter = EasyExcel.write("F:\\测试数据_副本3.xlsx").withTemplate("F:\\模板.xlsx").build(); WriteSheet writeSheet = EasyExcel.writerSheet().build(); FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); //填充列表数据 excelWriter.fill(DataGenerate.data(), fillConfig, writeSheet); //填充普通数据 Map<String, Object> map = new HashMap<String, Object>(); map.put("name", "狗子"); map.put("date", "2021-02-19"); excelWriter.fill(map, writeSheet); excelWriter.finish(); }
填充结果:
import com.alibaba.excel.EasyExcel; import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URLEncoder; @RestController public class SchoolDataController { /** * 导入Excel */ @PostMapping("/import") public String importExcel(MultipartFile file) throws IOException { EasyExcel.read(file.getInputStream(), SchoolData.class, new SchoolDataListener()).sheet().doRead(); return "success"; } /** * 导出Excel */ @GetMapping("/export") public void exportExcel(HttpServletResponse response) throws IOException { response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); // 这里URLEncoder.encode能够防止中文乱码 固然和easyexcel没有关系 String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20"); response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx"); // 这里须要设置不关闭流 EasyExcel.write(response.getOutputStream(), SchoolData.class).autoCloseStream(Boolean.FALSE).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("学校数据").doWrite(DataGenerate.data()); } }
参考:官方文档