EasyExcel操作Excel的导入和导出

从零开始学习SpringCloud

个人博客传送门


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模式。在上层做了模型转换的封装,让使用者更加简单方便。

产品经理: ***,帮我把数据库中的几个月的数据导成excel

程 序 员: 有什么要求呢?
产品经理: 没有要求只要能使用就可以了
程 序 员: 好的(心里面默默的,“又是一句话的需求”)

。。。。。。

20mins后

。。。。。。

程 序 员: 做好了(自豪感爆棚)
产品经理: 好的,干的漂亮(给你加鸡腿)

				点击按钮 loading 。。。
				
                一分钟后 loading 。。。

                三分钟后 loading 。。。

                五分钟后 还在loading。。。

产品经理: 你这功能不能用呀
程 序 员: ,难道出问题了?
EasyExcel操作Excel的导入和导出_第1张图片

程 序 员: 一顿猛如虎的操作过后,发现数据量太大了OOM

。。。。。。

20mins后

。。。。。。

程 序 员: 突然想到POI在处理的时候数据量太大,试试有什么方法

程 序 员: 一顿操作之后发现EasyExcel

。。。。。。

10mins后

。。。。。。

程 序 员: 替换完POI包之后,重写了方法,然后上线测试,完美的一波。

产品经理: 小伙子不错呀,下班了请你吃个大饼(画大饼)。

上面的情景是不是很熟悉,为了让广大猿猿们都能吃到大饼,我记录下了easyexcel的使用,用作分享和交流。

EasyExcel操作Excel的导入和导出_第2张图片

我们再来看下EasyExcel官方对自己的介绍,EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目,附带上官方已经经过性能测试的数据,可能由于服务器的配置的不同拿到的数据不一致。
64M内存1分钟内读取75M(46W行25列)的Excel

EasyExcel操作Excel的导入和导出_第3张图片

一.首先需要在pom.xml中引入easyexcel的包,如下:

 <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>easyexcel</artifactId>
      <version>1.1.2-beta5</version>
  </dependency>

二.接下来我编写了一个工具类用来解析和生成excel的类,代码如下。

包含基本的解析和生成文件的方法:

1. 生成文件的方法

EasyExcelUtils.writeExcelOneSheet();

2. 读取文件内容的方法

List<Object> list = EasyExcelUtils.readLessThan1000Row(is);

3. 文件格式的填充/合并等。
这里不去介绍关于样式的问题,有兴趣的话可以去官网了解下,提供了很详细的支持。
https://www.yuque.com/easyexcel/doc/fill

  EasyExcelUtils.java 工具类
 /**
   * 读取少于1000行数据
   *
   * @param is 文件流
   * @return
   */
  public static List<Object> readLessThan1000Row(InputStream is) {
      return readLessThan1000RowBySheet(is, null);
  }
​
    /**
     * 导出单个sheet
     * @param response
     * @param dataList
     * @param sheet
     * @param fileName
     * @throws UnsupportedEncodingException
     */
public static void writeExcelOneSheet(HttpServletResponse response,
                             List<? extends BaseRowModel> dataList, 
 Sheet sheet, String fileName) throws UnsupportedEncodingException {
  if (CollectionUtils.isEmpty(dataList)) {
      return;
  }
  // 如果sheet为空,则使用默认的
  if (null == sheet) {
      sheet = initSheet;
  }
  try {
      String value = "attachment; filename=" + new String(
              (fileName + ExcelTypeEnum.XLSX.getValue()).getBytes("gb2312"), "ISO8859-1");
      response.setContentType("multipart/form-data");
      response.setCharacterEncoding("utf-8");
      response.setContentType("application/vnd.ms-excel;charset=utf-8");
      response.setHeader("Content-disposition", value);
​
      ServletOutputStream out = response.getOutputStream();
      ExcelWriter writer = EasyExcelFactory.getWriter(out, ExcelTypeEnum.XLS, true);
      // 设置属性类
      sheet.setClazz(dataList.get(0).getClass());
      writer.write(dataList, sheet);
      writer.finish();
      out.flush();
  } catch (IOException e) {
      logger.error("导出失败,失败原因:{}", e);
  }
  }

三. 接下来我们需要创建一个model用来适配excel的格式,如下:

/**
 * @author :Mr.kk
 * @date: 2020/3/27 9:26
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExportModel extends BaseRowModel {
​
    @ExcelProperty(value = "编号", index = 0)
    private int num;
​
    @ExcelProperty(value = "姓名", index = 1)
    private String name;
​
    @ExcelProperty(value = "年龄", index = 2)
    private int age;
}
可以很清楚的看到对于excel的列和model的属性是一一对应的。

四. 接下来需要编写controller进行调用测试了。

  1. 先编写excel的导出,代码如下
/**
 * excel的导出
 */
@GetMapping("/exportExcel")
public void exportExcel(HttpServletRequest request, HttpServletResponse response){
  String fileName = null;
  try {
      List<ExportModel> dataList = new ArrayList<>();
      for (int i =0 ;i <= 3 ;i ++){
          dataList.add(new ExportModel(i,"Mr.kk"+i,18+i));
      }
      fileName = new String("excel导出".getBytes(), "UTF-8");
      EasyExcelUtils.writeExcelOneSheet(response,dataList,null,fileName);
  } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
  }
}
这里模仿数据库的查询,遍历生成了四条数据用于导出展示,启动工程执行,调用该接口,下载成功,内容如下。

EasyExcel操作Excel的导入和导出_第4张图片

2. 接下来编写excel文件的解析,代码如下:

/**
 * excel的导入
 */
@GetMapping("/importExcel")
public Object importExcel(@RequestParam(name = "file",required = true) MultipartFile excl){
  if(!excl.isEmpty()){//说明文件不为空
      try {
          InputStream is = new BufferedInputStream(excl.getInputStream());
          List<Object> list = EasyExcelUtils.readLessThan1000Row(is);
          //首先是读取行 也就是一行一行读,然后在取到列,遍历行里面的行,根据行得到列的值
          for (Object obj: list) {
              System.out.println(obj);
          }
      }catch (Exception e){
          e.printStackTrace();
      }
  }
  return "";
}

然后,我们调用接口将上一步生成的文件导入到系统中,打开控制台我们可以看到文件的内容全部被我们打印到了控制台。

EasyExcel操作Excel的导入和导出_第5张图片

五. 总结

 ***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模式。在上层做了模型转换的封装,让使用者更加简单方便。***

附上代码地址:https://github.com/zhaokuankuan/springboot-excel

长按二维码进行关注,获取更多的学习材料。
EasyExcel操作Excel的导入和导出_第6张图片

你可能感兴趣的:(javaWeb技术,springboot)