EasyExcel实现文件读取、导出、上传、下载操作
一、EasyExcel简介
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便
二、使用方法
1.引入依赖
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.8</version> </dependency>2.读取excel
(1)默认方式读取
通过EasyExcel.read()方式进行,参数依次为文件路径、要读取成指定文件的类、读取文件类的监听器,sheet中默认读取第一个sheet,也可以自己制定,读取文件时从第二行开始,可以按批次读取,也可以自定义读取
@Test public void easyExcelRead(){String path = "D:\\city_district.xlsx";EasyExcel.read(path, TeleCity.class, new TeleCityListener(teleCityService)).sheet("city市区表").doRead(); }监听器TeleCityListener,这里是继承了AnalysisEventListener,需要指定读取的类,因为没有被spring管理,所以这里需要new TeleCityListener(teleCityService),传入的teleCityService需要注入,方式来创建实例,通过构造器方式传入注入的dao或者service来赋值,调用相应的方法,插入数据库,也可以使用默认构造器,不会对数据库进行操作
@Slf4j public class TeleCityListener extends AnalysisEventListener<TeleCity> {/*** 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。*/private TeleCityService teleCityService;/*** 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来** @param teleCityService*/public TeleCityListener(TeleCityService teleCityService) {this.teleCityService = teleCityService;}public TeleCityListener(){}/*** 每隔100条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收*/private static final int BATCH_COUNT = 100;List<TeleCity> list = new ArrayList<TeleCity>();/*** 这个每一条数据解析都会来调用** @param teleCity* one row value. Is is same as {@link AnalysisContext#readRowHolder()}* @param analysisContext*/@Overridepublic void invoke(TeleCity teleCity, AnalysisContext analysisContext) {log.info("解析到一条数据:{}", JSON.toJSONString(teleCity));list.add(teleCity);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (list.size() >= BATCH_COUNT) {saveData();// 存储完成清理 listlist.clear();}}@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {}/*** 加上存储数据库*/private void saveData() {log.info("{}条数据,开始存储数据库!", list.size());teleCityService.insertTeleCityList(list);log.info("存储数据库成功!");} }(2)使用自定义的通用监听器读取文件
通过泛型和继承AnalysisEventListener来自定义通用的一个读取监听器,只读取数据,读到的数据全都封装在list里面,通过getList()即可得到返回的数据,想要处理哪种格式就传入相应的类即可
@Slf4j public class GeneralListener<T> extends AnalysisEventListener<T> {private List<T> list= Lists.newArrayList();@Overridepublic void invoke(T data, AnalysisContext context) {Assert.notNull(data,"导入数据不能为null");log.info("start read list of data :{}",JSON.toJSONString(data));list.add(data);}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {log.info("read data complete!");}public List<T> getList() {return list;} }创建一个实例,读取完毕后,调用getlist()方法
@Test public void generalExcelRead(){String path = "D:\\city_district.xlsx";//建立一个通用读取监听器,读取数据到这个里面,通过getList方式获取读取的数据GeneralListener<TeleCity> teleListener=new GeneralListener<>();//EasyExcel进行读取try{EasyExcel.read(path,TeleCity.class,teleListener).sheet("city市区表").doRead();}catch (Exception e){log.error("读取数据失败!",e);}log.info("读取到的数据大小为:{}", JSON.toJSONString(teleListener.getList().size()));//进行数据库插入操作teleCityService.insertTeleCityList(teleListener.getList()); }3.导出文件为Excel
使用EasyExcel.write()即可,里面参数为文件路径,要转出的文件内容,和sheet名称以及要导出的数据
@Test public void generateExcelWrite(){List<TeleCity> list=teleCityService.getList();List<TeleCityExcelDTO> exportList=JSON.parseArray(JSON.toJSONString(list),TeleCityExcelDTO.class);log.info("开始写入数据!");String path = "D:\\demo.xlsx";try {EasyExcel.write(path, TeleCityExcelDTO.class).sheet("模板").doWrite(exportList);}catch (Exception e){log.error("写入数据失败!",e);}log.error("写入数据成功!大小为{}", JSON.toJSONString(list.size())); }定义导出的数据文件格式:通过注释来指定哪些列不需要导出,导出列位置和名称以及相应的高度、宽度等
@Data public class TeleCityExcelDTO implements Serializable {/*** 忽略不读取和写入*/@ExcelIgnoreprivate static final long serialVersionUID = 8372588291576645501L;/*** 强制读取第三个 这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配*/@ExcelProperty(index = 0,value = "id")@ColumnWidth(10)private Long id;@ExcelProperty(index = 1,value = "城市名称")@ColumnWidth(20)private String cityName;@ExcelProperty(index = 2,value = "组织编码")@ColumnWidth(20)private String orgCode;@ExcelProperty(index = 3,value = "物流编码")@ColumnWidth(20)private String logisticCode;@ExcelProperty(index = 4,value = "省份Id")@ColumnWidth(10)private Long provinceId;@ExcelProperty(index = 5,value = "创建时间")@ColumnWidth(20)private String createTime;@ExcelProperty(index = 6,value = "更新时间")@ColumnWidth(20)private String updateTime; }4.Download下载文件
类似于上面导出文件,需要自定义导出文件内容格式。实际是将导出的文件写入response中,需要指定编码格式和输出流格式等。这里特别注意是需要使用Get方式请求的,将下载的数据在当前界面作为附件方式下载,不会打开新的界面
@GetMapping("/test17")public void testExportExcel(HttpServletResponse response) {//导出数据List<TeleCity> list = teleCityService.getList();List<TeleCityExcelDTO> exportList = JSON.parseArray(JSON.toJSONString(list), TeleCityExcelDTO.class);// 设置为导出件格式为excelresponse.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");String filePrefix="测试文件";try {// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode(filePrefix, "UTF-8").replaceAll("\\+", "%20");//Content-disposition 的 attachment参数将文件作为附件下载response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");EasyExcel.write(response.getOutputStream(), TeleCityExcelDTO.class).sheet("模板").doWrite(exportList);} catch (Exception e) {log.error("下载文件失败!", e);throw new BizException(ResponseCode.EXPORT_FILE_FAILURE);}log.info("下载数据大小为:{}", exportList.size());}5.Upload上传文件
类似于前面的读取excel文件,这里是通过前端选取文件,读入到输入流里面,然后通过监听器读取指定格式。注意接收文件的类型为:MultipartFile
@RequestMapping("/test18") public Response testUpLoadExcel(MultipartFile file){log.info("文件名称:{}",file.getName());//构建上传文件的数据格式GeneralListener<TeleCityExcelDTO> generalListener=new GeneralListener<>();try {EasyExcel.read(file.getInputStream(), TeleCityExcelDTO.class, generalListener).sheet().doRead();} catch (IOException e) {log.error("上传文件失败!", e);throw new BizException(ResponseCode.UP_LOAD_FILE_FAILURE);}return new Response("0","读取数据成功!",generalListener.getList().size()); }前端样式,注意读取文件的类型为:multipart/form-data,前端
<form action="/test/test18", method="post", enctype="multipart/form-data"><input type="file" name="file"/><input type="submit"> </form>总结
以上是生活随笔为你收集整理的EasyExcel实现文件读取、导出、上传、下载操作的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: Spring中策略模式实现方法
- 下一篇: 文件上传 upload-labs 1~2