SpringBoot中EasyExcel实现Excel文件的导入导出

前言

在我们日常的开发过程中经常会使用Excel文件的形式来批量地上传下载系统数据,我们最常用的工具是Apache poi,但是如果数据到底上百万时,将会造成内存溢出的问题,那么我们怎么去实现百万数据批量导入导出。

正文

Easyexcel

Easyexcel 是阿里巴巴的开源项目,用来优化Excel文件处理过程:

  • poi消耗内存严重:Java解析、生成Excel比较有名的框架有Apache poijxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但poi还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。
  • easyexcel针对内存做出了优化:重写了poi对07版Excel的解析,能够原本一个3M的excelPOI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出。

SpringBoot+ EasyExcel实现Excel文件的导入导出

导入依赖

<!--lombok-->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.2</version>
  <optional>true</optional>
</dependency>

<!--easyExcel-->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>easyexcel</artifactId>
  <version>1.1.2-beat1</version>
</dependency>

<!--fastjson-->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <exclusions>
    <exclusion>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
</dependency>

为了防止Excel文件被破坏在pom.xml添加以下内容

<build>
  <plugins>
    <!-- 让maven不编译xls文件,但仍将其打包 -->
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-resources-plugin</artifactId>
      <configuration>
        <nonFilteredFileExtensions>
          <nonFilteredFileExtension>xls</nonFilteredFileExtension>
          <nonFilteredFileExtension>xlsx</nonFilteredFileExtension>
        </nonFilteredFileExtensions>
      </configuration>
    </plugin>
  </plugins>
</build>

application.propertis:配置文件

#temp files
project.tmp.files.path=/Users/mac/Desktop/image/tmp/files/

在SpringBoot启动类添加临时文件设置

@Value("${project.tmp.files.path}")
public String filesPath;

@Bean
MultipartConfigElement multipartConfigElement() {
  MultipartConfigFactory factory = new MultipartConfigFactory();
  //设置路径xxx
  factory.setLocation(filesPath);
  return factory.createMultipartConfig();
}

ExcelUtil:Excel工具类

@Slf4j
public class ExcelUtil {
  private static Sheet initSheet;

  static {
    initSheet = new Sheet(1, 0);
    initSheet.setSheetName("sheet");
    //设置自适应宽度
    initSheet.setAutoWidth(Boolean.TRUE);
  }

  public static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) {
    try {
      response.setCharacterEncoding("UTF-8");
      response.setContentType("application/octet-stream;charset=utf-8");
      response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
      workbook.write(response.getOutputStream());
    } catch (IOException e) {
      // throw new NormalException(e.getMessage());
    }
  }

  /**
   * 读取少于1000行数据
   *
   * @param filePath 文件绝对路径
   * @return
   */
  public static List<Object> readLessThan1000Row(String filePath) {
    return readLessThan1000RowBySheet(filePath, null);
  }

  /**
   * 读小于1000行数据, 带样式
   * filePath 文件绝对路径
   * initSheet :
   * sheetNo: sheet页码,默认为1
   * headLineMun: 从第几行开始读取数据,默认为0, 表示从第一行开始读取
   * clazz: 返回数据List<Object> 中Object的类名
   */
  public static List<Object> readLessThan1000RowBySheet(String filePath, Sheet sheet) {
    if (!StringUtils.hasText(filePath)) {
      return null;
    }
    sheet = sheet != null ? sheet : initSheet;
    InputStream fileStream = null;
    try {
      fileStream = new FileInputStream(filePath);
      return EasyExcelFactory.read(fileStream, sheet);
    } catch (FileNotFoundException e) {
      log.info("找不到文件或文件路径错误, 文件:{}", filePath);
    } finally {
      try {
        if (fileStream != null) {
          fileStream.close();
        }
      } catch (IOException e) {
        log.info("excel文件读取失败, 失败原因:{}", e);
      }
    }
    return null;
  }

  /**
   * 读大于1000行数据
   *
   * @param filePath 文件觉得路径
   * @return
   */
  public static List<Object> readMoreThan1000Row(String filePath) {
    return readMoreThan1000RowBySheet(filePath, null);
  }

  /**
   * 读大于1000行数据, 带样式
   *
   * @param filePath 文件觉得路径
   * @return
   */
  public static List<Object> readMoreThan1000RowBySheet(String filePath, Sheet sheet) {
    if (!StringUtils.hasText(filePath)) {
      return null;
    }
    sheet = sheet != null ? sheet : initSheet;
    InputStream fileStream = null;
    try {
      fileStream = new FileInputStream(filePath);
      ExcelListener excelListener = new ExcelListener();
      EasyExcelFactory.readBySax(fileStream, sheet, excelListener);
      return excelListener.getDatas();
    } catch (FileNotFoundException e) {
      log.error("找不到文件或文件路径错误, 文件:{}", filePath);
    } finally {
      try {
        if (fileStream != null) {
          fileStream.close();
        }
      } catch (IOException e) {
        log.error("excel文件读取失败, 失败原因:{}", e);
      }
    }
    return null;
  }

  /**
   * 读大于1000行数据, 带样式
   *
   * @return
   */
  public static List<Object> readMoreThan1000RowBySheetFromInputStream(InputStream inputStream, Sheet sheet) {
    sheet = sheet != null ? sheet : initSheet;
    InputStream fileStream = null;
    ExcelListener excelListener = new ExcelListener();
    EasyExcelFactory.readBySax(inputStream, sheet, excelListener);
    return excelListener.getDatas();
  }

  /**
   * 生成excle
   *
   * @param filePath 绝对路径
   * @param data   数据源
   * @param head   表头
   */
  public static void writeBySimple(String filePath, List<List<Object>> data, List<String> head) {
    writeSimpleBySheet(filePath, data, head, null);
  }

  /**
   * 生成excle
   *
   * @param filePath 路径
   * @param data   数据源
   * @param sheet  excle页面样式
   * @param head   表头
   */
  public static void writeSimpleBySheet(String filePath, List<List<Object>> data, List<String> head, Sheet sheet) {
    sheet = (sheet != null) ? sheet : initSheet;
    if (head != null) {
      List<List<String>> list = new ArrayList<>();
      head.forEach(h -> list.add(Collections.singletonList(h)));
      sheet.setHead(list);
    }
    OutputStream outputStream = null;
    ExcelWriter writer = null;
    try {
      outputStream = new FileOutputStream(filePath);
      writer = EasyExcelFactory.getWriter(outputStream);
      writer.write1(data, sheet);
    } catch (FileNotFoundException e) {
      log.error("找不到文件或文件路径错误, 文件:{}", filePath);
    } finally {
      try {
        if (writer != null) {
          writer.finish();
        }

        if (outputStream != null) {
          outputStream.close();
        }

      } catch (IOException e) {
        log.error("excel文件导出失败, 失败原因:{}", e);
      }
    }
  }

  /**
   * 生成excle
   *
   * @param filePath 路径
   * @param data   数据源
   */
  public static void writeWithTemplate(String filePath, List<? extends BaseRowModel> data) {
    writeWithTemplateAndSheet(filePath, data, null);
  }

  /**
   * 生成excle
   *
   * @param filePath 路径
   * @param data   数据源
   * @param sheet  excle页面样式
   */
  public static void writeWithTemplateAndSheet(String filePath, List<? extends BaseRowModel> data, Sheet sheet) {
    if (CollectionUtils.isEmpty(data)) {
      return;
    }
    sheet = (sheet != null) ? sheet : initSheet;
    sheet.setClazz(data.get(0).getClass());
    OutputStream outputStream = null;
    ExcelWriter writer = null;
    try {
      outputStream = new FileOutputStream(filePath);
      writer = EasyExcelFactory.getWriter(outputStream);
      writer.write(data, sheet);
    } catch (FileNotFoundException e) {
      log.error("找不到文件或文件路径错误, 文件:{}", filePath);
    } finally {
      try {
        if (writer != null) {
          writer.finish();
        }
        if (outputStream != null) {
          outputStream.close();
        }
      } catch (IOException e) {
        log.error("excel文件导出失败, 失败原因:{}", e);
      }
    }

  }

  /**
   * 生成多Sheet的excle
   *
   * @param filePath       路径
   * @param multipleSheelPropetys
   */
  public static void writeWithMultipleSheel(String filePath, List<MultipleSheelPropety> multipleSheelPropetys) {
    if (CollectionUtils.isEmpty(multipleSheelPropetys)) {
      return;
    }
    OutputStream outputStream = null;
    ExcelWriter writer = null;
    try {
      outputStream = new FileOutputStream(filePath);
      writer = EasyExcelFactory.getWriter(outputStream);
      for (MultipleSheelPropety multipleSheelPropety : multipleSheelPropetys) {
        Sheet sheet = multipleSheelPropety.getSheet() != null ? multipleSheelPropety.getSheet() : initSheet;
        if (!CollectionUtils.isEmpty(multipleSheelPropety.getData())) {
          sheet.setClazz(multipleSheelPropety.getData().get(0).getClass());
        }
        writer.write(multipleSheelPropety.getData(), sheet);
      }

    } catch (FileNotFoundException e) {
      log.error("找不到文件或文件路径错误, 文件:{}", filePath);
    } finally {
      try {
        if (writer != null) {
          writer.finish();
        }

        if (outputStream != null) {
          outputStream.close();
        }
      } catch (IOException e) {
        log.error("excel文件导出失败, 失败原因:{}", e);
      }
    }
  }

  /*********************匿名内部类开始,可以提取出去******************************/
  @Data
  public static class MultipleSheelPropety {
    private List<? extends BaseRowModel> data;
    private Sheet sheet;
  }

  /**
   * 解析监听器,
   * 每解析一行会回调invoke()方法。
   * 整个excel解析结束会执行doAfterAllAnalysed()方法
   *
   * @author: chenmingjian
   * @date: 19-4-3 14:11
   */
  @Getter
  @Setter
  public static class ExcelListener extends AnalysisEventListener {
    private List<Object> datas = new ArrayList<>();

    /**
     * 逐行解析
     * object : 当前行的数据
     */
    @Override
    public void invoke(Object object, AnalysisContext context) {
      //当前行
      // context.getCurrentRowNum()
      if (object != null) {
        datas.add(object);
      }
    }

    /**
     * 解析完所有数据后会调用该方法
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
      //解析结束销毁不用的资源
    }

  }

  /************************匿名内部类结束,可以提取出去***************************/
}

CommonUtil:工具类

public class CommonUtil {

/**
 * 生成32位编码,不含横线
 *
 * @return uuid串
 */
public static String getUUID() {
  String uuid = UUID.randomUUID().toString().trim().replaceAll("-", "");
  return uuid.toUpperCase();
}

/**
 * 得到当前日期格式化后的字符串,格式:yyyy-MM-dd(年-月-日)
 * @return 当前日期格式化后的字符串
 */
public static String getTodayStr(){
  return new SimpleDateFormat("yyyy-MM-dd").format(new Date()) ;
}

/**
 * 将对象转化成json
 *
 * @param t
 * @return
 * @throws JsonProcessingException
 */
public static <T> String toJson(T t) throws JsonProcessingException {
  return OBJECT_MAPPER.get().writeValueAsString(t);
}

}

UserPojoRes:实体类

@Setter
@Getter
@ToString
public class UserPojoRes extends BaseRowModel implements Serializable {
  private static final long serialVersionUID = -2145503717390503506L;

  /**
   * 主键
   */
  @ExcelProperty(value = "ID", index = 0)
  private String id;
  /**
   * 姓名
   */
  @ExcelProperty(value = "用户名", index = 1)
  private String name;

  public UserPojoRes(String id, String name) {
    this.id = id;
    this.name = name;
  }

  public UserPojoRes(){

  }
}

验证

模板下载

这里将模板文件放在resources

@GetMapping("/exportExcelTempalte")
@ApiOperation(value = "下载导入模板")
public void exportExcelTempalte(HttpServletResponse response) throws Exception {
  //Resource目录中的文件
  String filePath = "/excels/导入模板.xlsx";
  ClassPathResource classPathResource = new ClassPathResource(filePath);
  Workbook workbook=WorkbookFactory.create(classPathResource.getInputStream());
  ExcelUtil.downLoadExcel("导入模板.xlsx", response, workbook);
}

Excel文件导入

@PostMapping("/importExcel")
@ApiOperation(value = "Excel文件导入")
public Response importExcel(HttpServletRequest request, MultipartFile file, HttpServletResponse response) throws Exception {
  List<Object> objects = ExcelUtil.readMoreThan1000RowBySheetFromInputStream(file.getInputStream(),null);
  List<UserPojoRes> list = new ArrayList<>();
  for (Object o : objects) {
    UserPojoRes userPojoRes = new UserPojoRes();
    List<String> stringList = (List<String>) o;
    userPojoRes.setId(stringList.get(0) != null ? stringList.get(0).toString() : "");
    userPojoRes.setName(stringList.get(1) != null ? stringList.get(0).toString() : "");
    list.add(userPojoRes);
  }
  String json = CommonUtil.toJson(list);
  return new Response(json);
}

Excel文件导出

@Value("${project.tmp.files.path}")
public String filesPath;

@GetMapping("/exportExcel")
@ApiOperation(value = "Excel文件导出")
public void exportExcel(HttpServletResponse response) throws Exception {

  //创建临时文件
  String path = filesPath + CommonUtil.getUUID() + ".xlsx";
  List<UserPojoRes> list = new ArrayList<>();
  UserPojoRes userPojoRes = new UserPojoRes("009", "张三");
  UserPojoRes userPojoRes1 = new UserPojoRes("009", "李四");
  list.add(userPojoRes);
  list.add(userPojoRes1);
  ExcelUtil.writeWithTemplate(path, list);
  // 根据excel创建对象
  Workbook workbook = WorkbookFactory.create(new FileInputStream(path));
  String fileName = "用户模块" + CommonUtil.getTodayStr() + ".xlsx";
  ExcelUtil.downLoadExcel(fileName, response, workbook);
}

到此这篇关于SpringBoot中EasyExcel实现Excel文件的导入导出的文章就介绍到这了,更多相关Java Excel文件导入导出内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Springboot使用POI实现导出Excel文件示例

    前面讲述了使用POI导出Word文件和读取Excel文件,这两个例子都相对简单,接下来要讲述的使用POI导出Excel文件要复杂得多,内容也会比较长. 创建表头信息 表头信息用于自动生成表头结构及排序 public class ExcelHeader implements Comparable<ExcelHeader>{ /** * excel的标题名称 */ private String title; /** * 每一个标题的顺序 */ private int order; /** * 说对

  • springboot实现上传并解析Excel过程解析

    添加pom依赖 <!-- excel解析包 --> <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> <!--处理2003 excel--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.16<

  • SpringBoot实现Excel文件批量上传导入数据库

    Spring boot + Spring data jpa + Thymeleaf 批量插入 + POI读取 + 文件上传 pom.xml: <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <versi

  • 基于SpringBoot框架管理Excel和PDF文件类型

    一.文档类型简介 1.Excel文档 Excel一款电子表格软件.直观的界面.出色的计算功能和图表工具,在系统开发中,经常用来把数据转存到Excel文件,或者Excel数据导入系统中,这就涉及数据转换问题. 2.PDF文档 PDF是可移植文档格式,是一种电子文件格式,具有许多其他电子文档格式无法相比的优点.PDF文件格式可以将文字.字型.格式.颜色及独立于设备和分辨率的图形图像等封装在一个文件中.该格式文件还可以包含超文本链接.声音和动态影像等电子信息,支持特长文件,集成度和安全可靠性都较高.

  • Springboot POI导出Excel(浏览器)

    本文实例为大家分享了Springboot POI导出Excel的具体代码,供大家参考,具体内容如下 需求:页面根据查询条件导出(浏览器) 由于本次导出数据量较大,这里采用XSSFWorkbook多线程进行导出,注:XSSFWorkbook导出excel文件结尾为:".xlsx". 导出不需要返回,如有返回则会报异常! //Controller @RequestMapping("/stateExport") public void stateExport(HttpSe

  • SpringBoot整合POI导出通用Excel的方法示例

    一.准备工作 1.pom依赖 在pom.xml中加入POI的依赖 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.11-beta1</version> </dependency> <dependency> <groupId>org.apache.poi

  • SpringBoot使用POI进行Excel下载

    本文实例为大家分享了SpringBoot使用POI进行Excel下载的具体代码,供大家参考,具体内容如下 使用poi处理Excel特别方便,此处将处理Excel的代码分享出来. 1.maven引用 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependenc

  • SpringBoot中EasyExcel实现Excel文件的导入导出

    前言 在我们日常的开发过程中经常会使用Excel文件的形式来批量地上传下载系统数据,我们最常用的工具是Apache poi,但是如果数据到底上百万时,将会造成内存溢出的问题,那么我们怎么去实现百万数据批量导入导出. 正文 Easyexcel Easyexcel 是阿里巴巴的开源项目,用来优化Excel文件处理过程: poi消耗内存严重:Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的

  • SpringBoot集成EasyExcel实现Excel导入的方法

    第一次正式的写文章进行分享,如果文章中有什么问题,欢迎大家在文末的群内反馈. 一.背景 为什么会用Easyexcel来做Excel上传 平时项目中经常使用EasyExcel从本地读取Excel中的数据,还有一个前端页面对需要处理的数据进行一些配置(如:Excel所在的文件夹,Excel的文件名,以及Sheet列名.处理数据需要的某些参数),由于每次都是读取的本地的文件,我就在想,如果某一天需要通过前端上传excel给我,让我来进行处理我又应该怎么办呢?我怎么才能在尽量少修改代码的前提下实现这个功

  • Java+EasyExcel实现文件的导入导出

    目录 引言 效果图 项目结构 核心源码 核心实体类 核心监听器类 EasyExcel导入文件 EasyExcel导出文件 引言 项目中需要Excel文件的导入与导出Excel并下载,例如,导入员工信息,导出员工信息,手动输入比较繁琐,所以本篇博文教大家如何在Java中导入Excel文件与导出Excel文件 技术栈 Excel工具:EasyExcel 选用框架:Spring.Spring MVC.MyBatis(SSM) 项目构建管理工具:Maven 需求: 1.要求利用excel工具实现员工信息

  • SpringBoot整合EasyExcel实现Excel表格导出功能

    目录 栗子 1.组件介绍 2.配置文件 SpringBoot项目pom.xml 3.项目代码 项目结构 ExportController.java Mock.java CitySheet.java CompanySheet.java UserSheet.java SpringBootEasyexcelApplication.java 4.效果展示 单个sheet导出 多个sheet导出 5.总结 栗子 在后端管理系统的开发中,经常有需要导出当前表格数据的功能,有些前端表格组件可以直接做到,但是不

  • C++ 中实现把EXCEL的数据导入数据库(ACCESS、MSSQL等)实例代码

    C++ 中实现把EXCEL的数据导入数据库(ACCESS.MSSQL等)实例代码 在把EXCEL的数据导入数据库之前,先进行一些简单的准备工作: 1.把数据所在的EXCEL表另保存为DBF 4格式. 2.打开BCB,添加AdoTable(改名为DBFTable)和DataSource这两个控件 OK,准备工作,到此结束,剩下的就是打代码了 1.在Form_Load()事件中,加入以下代码: AnsiString filepath=ExtractFilePath(FileName); //File

  • Java实现上传Excel文件并导入数据库

    目录 Java实现上传Excel文件并导出到数据库 1.导入依赖 2.domain 3.utils 4.Controller 5.xml Java实现上传Excel文件并导出到数据库 1.导入依赖 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version> </de

  • Java Hutool工具实现验证码生成及Excel文件的导入和导出

    目录 1.Hutool工具简介 2.Hutool的相关依赖 3.验证码工具 4.excel工具 1.Hutool工具简介 HuTool工具(糊涂工具),第三方插件工具,简化操作,是国产的一个产品,界面简洁易懂,比较人性化.(上班可能经常用的到,建议收藏起来) Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以"甜甜的". 2.Hutool的相关依赖 maven项目在pom.xml添

  • yii2.0框架实现上传excel文件后导入到数据库的方法示例

    本文实例讲述了yii2.0框架实现上传excel文件后导入到数据库的方法.分享给大家供大家参考,具体如下: Model模型 <?php /** * 描述... * @author zcy * @date 2019/8/13 */ namespace app\models; use yii\base\Model; use yii\db\ActiveRecord; use yii\web\UploadedFile; class uploadForm extends ActiveRecord { pu

  • 利用phpExcel实现Excel数据的导入导出(全步骤详细解析)

    很多文章都有提到关于使用phpExcel实现Excel数据的导入导出,大部分文章都差不多,或者就是转载的,都会出现一些问题,下面是本人研究phpExcel的使用例程总结出来的使用方法,接下来直接进入正题. 首先先说一下,本人的这段例程是使用在Thinkphp的开发框架上,要是使用在其他框架也是同样的方法,很多人可能不能正确的实现Excel的导入导出,问题基本上都是phpExcel的核心类引用路径出错,如果有问题大家务必要对路劲是否引用正确进行测试. (一)导入Excel 第一,在前台html页面

  • 精妙的SQL和SQL SERVER 与ACCESS、EXCEL的数据导入导出转换

    * 说明:复制表(只复制结构,源表名:a 新表名:b)       select * into b from a where 1<>1     * 说明:拷贝表(拷贝数据,源表名:a 目标表名:b)       insert into b(a, b, c) select d,e,f from b;     * 说明:显示文章.提交人和最后回复时间       select a.title,a.username,b.adddate from table a,(select max(adddate

随机推荐