easyExcel简介
Java领域解析、⽣成Excel⽐较有名的框架有Apache poi、jxl等。但他们都存在⼀个严重的问题就是⾮常的耗内存。如果你的系统并发量不⼤的话可能还⾏,但是⼀旦并发上来后⼀定会OOM或者JVM频繁的full gc。
easyExcel是阿⾥巴巴开源的⼀个excel处理框架,以使⽤简单、节省内存著称。
M内存1分钟内读取75M(46W⾏25列)的Excel(当然还有急速模式能更快,但是内存占⽤会在100M多⼀点)
easyExcel能⼤⼤减少占⽤内存的主要原因是在解析Excel时没有将⽂件数据⼀次性全部加载到内存中,⽽是从磁盘上⼀⾏⾏读取数据,逐个解析。下图是easyExcel和POI在解析Excel时的对⽐图。
easyExcel采⽤⼀⾏⼀⾏的解析模式,并将⼀⾏的解析结果以观察者的模式通知处理(AnalysisEventListener)。
上⾯简要介绍了easyExcel的特点和原理,关于easyExcel的其他问题可以先参考下这个。下⾯就通过代码来介绍下怎么使⽤easyExcel。快速使⽤指南
⽂件上传读取Excel
下⾯通过⼀个读取⽤户信息的列⼦来展⽰下怎么使⽤easyExcel。step1:创建⽤户信息类@Data
public class UserInfo extends BaseRowModel { @ExcelProperty(index = 0) private String name; @ExcelProperty(index = 1) private int age;
@ExcelProperty(index = 2) private String address;
}
step2:创建AnalysisEventListener⼦类/**
* 每解析⼀⾏会回调invoke()⽅法。
* 整个excel解析结束会执⾏doAfterAllAnalysed()⽅法 */
//有个很重要的点 不能被spring管理,要每次读取excel都要new。
//这边就会有⼀个问题:如果UserInfoDataListener中需要⽤到Spring中的主键怎么办?public class UserInfoDataListener extends AnalysisEventListener //每次读取100条数据就进⾏保存操作 private static final int BATCH_COUNT = 100; //由于每次读都是新new UserInfoDataListener的,所以这个list不会存在线程安全问题 List //这个组件是Spring中的组件,这边推荐两种⽅法注⼊这个组件 //第⼀种就是提供⼀个UserInfoDataListener的构造⽅法,这个⽅法提供⼀个参数是UserInfoDataListener类型 //另外⼀种⽅法就是将 UserInfoDataListener 这个类定义成 UserService 实现类的内部类(推荐这种⽅式) //private UserService userService; @Override public void invoke(UserInfo data, AnalysisContext analysisContext) { logger.info(\"解析到⼀条数据:{}\ list.add(data); if (list.size() >= BATCH_COUNT) { saveData(); // 存储完成清理 list list.clear(); } } @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { // 这⾥也要保存数据,确保最后遗留的数据也存储到数据库 saveData(); logger.info(\"所有数据解析完成!\"); } private void saveData() { logger.info(\"{}条数据,开始存储数据库!\ //保存数据 //userService.save(list); logger.info(\"存储数据库成功!\"); } } step3: 读取excel public class EasyExcelDemo { public static void main(String[] args) throws Exception { InputStream fis = new FileInputStream(\"D:\\\\UserInfo.xlsx\"); AnalysisEventListener listener = new UserInfoDataListener(); ExcelReader excelReader = EasyExcel.read(fis, UserInfo.class, listener).build(); ReadSheet readSheet = EasyExcel.readSheet(0).build(); ReadSheet readSheet2 = EasyExcel.readSheet(1).build(); excelReader.read(readSheet); // 这⾥千万别忘记关闭,读的时候会创建临时⽂件,到时磁盘会崩的 excelReader.finish(); }} 只需要上⾯3步就能进⾏Excel的读取了。⽂件下载Excelpublic class ExcelUtil { public static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception{ try{ fileName = URLEncoder.encode(fileName,\"utf-8\"); response.setContentType(\"application/vnd.ms-excel\"); response.setCharacterEncoding(\"utf-8\"); //此处指定了⽂件类型为xls,如果是xlsx的,请⾃⾏替换修改 response.setHeader(\"Content-Disposition\ response.setHeader(\"Pragma\ response.setHeader(\"Cache-Control\ response.addHeader(\"Cache-Control\ return response.getOutputStream(); } catch (IOException e){ throw new Exception(\"导出⽂件失败!\"); } } public static void writeExcel(HttpServletResponse response, List extends BaseRowModel> list, String fileName, String sheetName, Class clazz) throws Exception { ExcelWriter writer = new ExcelWriter(getOutputStream(fileName, response), ExcelTypeEnum.XLS); Sheet sheet = new Sheet(1, 0, clazz); sheet.setSheetName(sheetName); writer.write(list, sheet); writer.finish(); }} 在Controller中我们只要像下⾯这种⽅式调⽤就⾏了。 @RequestMapping(value = \"/file/testExcelDownload\") public void testExcelDownload(HttpServletRequest request,HttpServletResponse response){ //以下信息从数据库中查出 List info1.setIssuerName(\"name1\"); info1.setRiskLevel(\"level1\"); info2.setIssuerName(\"name1\"); info2.setRiskLevel(\"level1\"); try { String fileName = \"excelInfo\"; String sheetName = \"sheet1\"; ExcelUtil.writeExcel(response, excelInfos, fileName, sheetName, ExcelInfo.class); } catch(Exception e){ log.error(\"模板下载失败\ } } 在导出Excel的部分,easyExcel还提供了⾃定义样式,插⼊表格,插⼊图⽚等其他功能,还有⼀个⽐较有意思的功能就是Excel模板填充的功能。详细的功能信息参考。⼀些⼩建议 尽量使⽤DTO的模式导出Excel给导出的Excel建⽴单独的DTO模型 exportWithEasyExcel(excelDate,XXDTO.class,\"订单.xlsx\订单\"); private void exportWithEasyExcel(List rows, Class clazz, String fileName,String sheetName) { try { HttpServletResponse response = WebSessionUtil.getResponse(); HttpServletRequest request = WebSessionUtil.getRequest(); String newFileName = encodeFileName(request, fileName); response.setContentType(\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8\"); response.setHeader(\"Content-Disposition\ ServletOutputStream out = response.getOutputStream(); EasyExcel.write(out,clazz).autoCloseStream(Boolean.FALSE).sheet(StringUtils.isEmpty(sheetName)?\"default\":sheetName) .doWrite(rows); } catch (IOException e) { throw new CivOprRunTimeException(ResponseType.DOWNLOAD_FILE_FAIL_CODE, e); } } private String encodeFileName(HttpServletRequest req, String oldFileName) throws UnsupportedEncodingException { // IE9之前包括IE9都包含MSIE;IE10之后都包含Trident;edge浏览器包含Edge String filename = \"\"; String userAgent = req.getHeader(\"User-Agent\"); if (userAgent.contains(\"MSIE\") || userAgent.contains(\"Trident\") || userAgent.contains(\"Edge\")) { filename = URLEncoder.encode(oldFileName, \"UTF-8\"); } else { filename = new String(oldFileName.getBytes(\"UTF-8\"), \"ISO8859-1\"); } return filename; } 使⽤模板模式 easyExcel也⽀持先定义模板,然后准备数据,模板中使⽤占位符的形式取数据。使⽤excel-wrapper对导⼊的数据进⾏注解校验参考 (导⼊Excel,并对字段进⾏校验)官⽹: 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- 69lv.com 版权所有 湘ICP备2023021910号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务