zoukankan      html  css  js  c++  java
  • Springboot---后台导出功能,easyExcel

    Sprintboot+vuejs+easyExcel实现excel导出功能

    一、背景

    前段时间,有个需求,想要做一个excel导出功能,用来把查询到的数据进行导出。第一次做,所以搜了大量的资料,分为两种,一个是查询出来前端用XLSX和File-saver导出,一个是springboot导出,返回文件流。这次就做一个后端导出的记录吧!

    二、几种excel导出方式比较

    用 Apache 开源框架 poi, 或者 jxl 都可以实现。

    传统 Excel 框架的不足:Apache poi、jxl 都存在生成 excel 文件不够简单优雅快速外,它们都还存在一个严重的问题,那就是非常耗内存严重时会导致内存溢出

    POI 虽然目前来说,是 excel 解析框架中被使用最广泛的,但这个框架并不完美。

    为什么这么说呢?

    开发者们大部分使用 POI,都是使用其 userModel 模式。而 userModel 的好处是上手容易使用简单,随便拷贝个代码跑一下,剩下就是写业务转换了,虽然转换也要写上百行代码,但是还是可控的。

    然而 userModel 模式最大的问题是在于,对内存消耗非常大,一个几兆的文件解析甚至要用掉上百兆的内存。现实情况是,很多应用现在都在采用这种模式,之所以还正常在跑是因为并发不大,并发上来后,一定会OOM或者频繁的 full gc。

    三、easyExcel

     由阿里出品的easyExcel,gitHub地址:https://github.com/alibaba/easyexcel

    四、快速上手

     1.添加依赖

    <!--alibaba easyexcel-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>easyexcel</artifactId>
      <version>1.1.2-beta5</version>
    </dependency>
    <!--lombok-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>

    lombok这个依赖在后面如果使用model接受数据设置excel的列名的时候需要用到。

    2.pojo设置列名(创建需要写入的数据集

    正常业务中,这块都是从数据库中查询出来的。

    @Data
    public class WriteModel extends BaseRowModel {
    
        @ExcelProperty(value = "姓名", index = 0)
        private String name;
    
        @ExcelProperty(value = "密码", index = 1)
        private String password;
    
        @ExcelProperty(value = "年龄", index = 2)
        private Integer age;
    }

    ExayExcel 提供注解的方式, 来方便的定义 Excel 需要的数据模型:

    • :首先,定义的写入模型必须要继承自 BaseRowModel.java;
    • :通过 @ExcelProperty 注解来指定每个字段的列名称,以及下标位置

    3.逻辑代码,生成excel

    1)生成到本地

    public void writeExcel1(String pathName,List<? extends BaseRowModel> dataInfo) throws Exception {
      // 文件输出位置
      OutputStream out = new FileOutputStream(filePath);
    
      ExcelWriter writer = EasyExcelFactory.getWriter(out);
    
      // 写仅有一个 Sheet 的 Excel 文件, 此场景较为通用
      Sheet sheet1 = new Sheet(1, 0, WriteModel.class);
    
      // 第一个 sheet 名称
      sheet1.setSheetName("第一个sheet");
    
      // 写数据到 Writer 上下文中
      // 入参1: 创建要写入的模型数据
      // 入参2: 要写入的目标 sheet
      writer.write(dataInfo, sheet1);
    
      // 将上下文中的最终 outputStream 写入到指定文件中
      writer.finish();
    
      // 关闭流
      out.close();
    }

    2)生成文件流返回给前端

    public void cooperation(HttpServletResponse response,String fileName,String sheetName,List<? extends BaseRowModel> dataInfo,Class<? extends BaseRowModel> clazz) {
            ExcelWriter writer = null;
            OutputStream out = null;
            out = response.getOutputStream();
            writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);
            Sheet sheet1 = new Sheet(1, 0,clazz);
            sheet1.setSheetName("第一个sheet");
            writer.write(dataInfo, sheet1);
            writer.finish();
            response.setContentType("multipart/form-data");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename="+fileName+".xlsx");
            response.setHeader("FileName", fileName+".xlsx");
            out.flush();
            }
        }

     前端主要是发送请求,当成功的时候,就接受文件流,创建一个超链接a,点击

    axios({
            method: "post",
            url: "/excel",
            data:this.query.data,
            responseType: "blob"
          })
            .then(res => {
             // console.log(decodeURI(res.headers['filename']));
              const link = document.createElement("a");
              let blob = new Blob([res.data], { type: "multipary/form-data" });
              link.style.display = "none";
              link.href = URL.createObjectURL(blob);
              link.setAttribute("download", decodeURI(res.headers['filename']));
              document.body.appendChild(link);
              link.click();
              document.body.removeChild(link);
            })
            .catch(error => {
              this.$Notice.error({
                title: "错误",
                desc: "系统数据错误"
              });
              console.log(error);
            });
        },

    3)动态生成excel的表头

    有的时候我们不知道表头是什么,什么形式,有哪些,需要通过查询数据库才能获得,这个时候我们就需要mybatis先查出数据库中的字段名,然后创建表头,之后再进行数据填充

    因为easyExcel的函数编写,需要给他List<List<String>> 类型的表头信息,以及List<List<object>>类型的表内容信息

    而mybatis中生成返回的仅仅是List<String >和List<HashHap<String,String>>类型的,所以需要自己进行转换一下

    public void cooperation(HttpServletResponse response,String fileName,String sheetName,List<List<Object>> dataInfo,List<List<String>> params) {
            ExcelWriter writer = null;
            OutputStream out = null;
            out = response.getOutputStream();
            writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);
            Sheet sheet1 = new Sheet(1, 0);
            sheet1.setSheetName("第一个sheet");
            sheet1.setHead(params);
            writer.write1(dataInfo, sheet1);
            writer.finish();
            response.setContentType("multipart/form-data");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename="+fileName+".xlsx");
            response.setHeader("FileName", fileName+".xlsx");
            out.flush();
            }
        }

    以上就是我在写的过程中用到的三种生成excel的方法。更多详细的内容可以去github查看

  • 相关阅读:
    手把手带你玩转 DialogFragment
    紧张的去京东面试7,没想到可以成功拿下offer
    这个有点强,MySQL常用优化指南及大表优化思路(值得收藏)
    Java程序员两年经验斩获头条 Offer,技术杠杠的
    为什么大家都说 SELECT * 效率低
    Java程序员想要靠外包刷题,结果却大跌眼镜,心态都崩了
    一次请求在SpringMVC核心执行流程
    工作三年经验,一年内我靠这份javaBAT进阶面试题从13K到大厂25K
    用了这么久的数据库连接池,你知道原理吗?
    poj 3295 Tautology(栈)
  • 原文地址:https://www.cnblogs.com/charles8866/p/11304251.html
Copyright © 2011-2022 走看看