EasyExcel官方地址:
EasyExcel简介
Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或 者JVM频繁的full gc。
EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一 行行读取数据,逐个解析。
EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理 (AnalysisEventListener)
SpringBoot整合easyexcel
easyexcel提供读、写、填充三种功能。这里我们采用模板填充的方式实现excel导出。
1.引入依赖
com.alibaba easyexcel 3.1.0
2.模板文件
我们将模板excel放在resource下:
3.数据准备
4.数据传输对象
@Datapublic class FtBranchDTO { private String branchName; private Integer branchPeople; private String branchPhone; private String branchManager; private String branchGrade;}@Datapublic class FtUserDTO { private String name; private Integer age; private String phone; private String sex; private BigDecimal grade;}@Datapublic class GradeAvgDTO { private BigDecimal userAverage;}@Datapublic class PeopleSumDTO { private Integer sum;}
4.导出excel
@Slf4j@RestController@RequestMapping("/excelExport")public class ExcelExportController { @Autowired private FtUserService ftUserService; @Autowired private FtBranchService ftBranchService; @GetMapping public void excelExport(HttpServletResponse response){ //员工信息 平均成绩 List ftUserEntities = ftUserService.list(); List ftUserDTOS = ftUserEntities.stream().map(ftUserEntity -> { FtUserDTO ftUserDTO = new FtUserDTO(); BeanUtils.copyProperties(ftUserEntity,ftUserDTO); return ftUserDTO; }).collect(Collectors.toList()); GradeAvgDTO gradeAvgDTO = ftUserService.getAverageGrade(); //部门信息 员工总数 List ftBranchEntities = ftBranchService.list(); List ftBranchDTOS = ftBranchEntities.stream().map(ftBranchEntity -> { FtBranchDTO ftBranchDTO = new FtBranchDTO(); BeanUtils.copyProperties(ftBranchEntity,ftBranchDTO); return ftBranchDTO; }).collect(Collectors.toList()); PeopleSumDTO peopleSumDTO = ftBranchService.getPeopleSum(); //获取模板(模板你可以放在任何位置,前提是你能获取到。这里放在resource下) ClassPathResource couponOrderTemplateResource = new ClassPathResource("userInfo.xlsx"); response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); String excelFileName = URLEncoder.encode("公司信息", StandardCharsets.UTF_8) .replaceAll("\\+", "%20"); response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); // attachment这个代表要下载的,如果去掉就直接打开了(attachment-作为附件下载,inline-在线打开) // excelFileName是文件名,另存为或者下载时,为默认的文件名 response.setHeader("Content-disposition","attachment;filename=" + excelFileName + ".xlsx"); response.setHeader("Content-Type","application/octet-stream;charset=utf-8"); InputStream templateInputStream = null; ExcelWriter excelWriter = null; WriteSheet userSheet = null; WriteSheet branchSheet = null; ServletOutputStream outputStream = null; try { outputStream = response.getOutputStream(); templateInputStream = couponOrderTemplateResource.getInputStream(); } catch (IOException e) { log.error("获取模板失败"); } // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行,然后下面的数据往后移动。默认 是false,会直接使用下一行,如果没有则创建。 // forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了,所以慎用 // 简单的说 如果你的模板有list,且list不是最后一行,下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存 // 如果数据量大 list不是最后一行 参照下一个 FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); excelWriter = EasyExcel.write(outputStream).withTemplate(templateInputStream).build(); //创建第一个sheet userSheet = EasyExcel.writerSheet("员工信息").build(); //填充 excelWriter.fill(ftUserDTOS,fillConfig,userSheet);//员工基础信息 excelWriter.fill(gradeAvgDTO,userSheet);//员工平均成绩 //创建第二个sheet branchSheet = EasyExcel.writerSheet("部门信息").build(); //填充 excelWriter.fill(ftBranchDTOS,fillConfig,branchSheet);//部门基础信息 excelWriter.fill(peopleSumDTO,branchSheet);//总人数 //关闭 excelWriter.finish(); IOUtils.closeQuietly(templateInputStream); IOUtils.closeQuietly(outputStream); IOUtils.closeQuietly(excelWriter); }}
5.测试excel导出
效果图如下: