需求:测试EasyExcel的导入导出使用、性能,测试数据量3个字段100万条数据;

测试环境:idea + maven + springboot + mybatis-plus + mysql + swagger

文章目录(目录跳转可能会不准确,建议直接Ctrl+F搜目录吧)

前言

一、项目整体目录

二、数据库

1.创建表

三、后端

1、pom.xml文件

2、yml文件(导入、导出共用代码)

3、共用的代码文件(使用其他框架的可以忽略①②③④⑤操作)

① 实体类对象TestExcel(导入、导出共用代码)

② mapper层(导入、导出共用代码)

③ service层(导入、导出共用代码)

④ impl实现层(导入、导出共用代码)

⑤ 分页工具(导入、导出共用代码)

⑥ EasyExcel的工具类(最主要的文件,如果使用的其它框架,可以忽略上面的代码,注释会尽量写的详细一些)

4、使用for循环创建数据,并导出成excel文件(controller的依赖全放在这里了,后面不再重复写)

5、 excel导入

6、excel导出

四、总结


前言

导入流程:用户上传文件-->后端获取文件流-->侦听器读取文件-->批量插入数据库
导出流程:用户点击按钮-->调用后端接口-->分页查询需要导出的数据-->导出成excel文件

因为是测试项目,为了更方便、明了,所以所有操作均放在了controller里,正式使用时注意放入接口实现层impl里,

如果是使用其它框架的,请忽略“后端目录下的①②③④⑤操作”,改用自己框架的方法即可

一、项目整体目录

二、数据库

1.创建表

CREATE TABLE test_excel (user_id varchar(255) NOT NULL COMMENT '表主键id',user_name varchar(255) NOT NULL COMMENT '用户姓名,不能为空',user_age varchar(255) DEFAULT NULL COMMENT '用户年龄,允许为空',user_cardid varchar(255) NOT NULL COMMENT '身份证号,不能为空,不允许重复',PRIMARY KEY (user_id)
);

三、后端

1、pom.xml文件

主要依赖是:

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.10</version>
</dependency>

全部依赖(根据自己的需求选择依赖,不用全部导入):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.3</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.bug</groupId><artifactId>bug</artifactId><version>0.0.1-SNAPSHOT</version><name>my_springboot1</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.0</version></dependency><dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.3.3</version></dependency><dependency><groupId>org.testng</groupId><artifactId>testng</artifactId><version>RELEASE</version><scope>compile</scope></dependency><!-- ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ itextpdf依赖包 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ --><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.6</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>itext-asian</artifactId><version>5.2.0</version></dependency><!-- ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ itextpdf依赖包 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ --><!-- ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 用于测试依赖包 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13</version></dependency><!-- ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 用于测试依赖包 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ --><!-- ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ slf4j+logback包 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.30</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId></dependency><!-- ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ slf4j+logback包 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ --><!-- ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ json包 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency><!-- ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ json包 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ --><!-- ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 过滤器 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.4</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.4</version></dependency><!-- ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 过滤器 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ --><!-- ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ swagger ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version></dependency><!-- ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ swagger ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ --><!-- ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 连接数据库-MySQL-mybatis-plus ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId><version>2.5.3</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.2</version></dependency><!-- ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 连接数据库-MySQL-mybatis-plus  ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ --><!-- ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ Easy Excel ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.10</version></dependency><!-- ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ Easy Excel ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ --><!-- ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ lombok ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope></dependency><!-- ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ lombok ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ --></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.4.3</version></plugin></plugins><resources><resource><directory>src/main/java</directory><excludes><exclude>**/*.java</exclude></excludes></resource><resource><directory>src/main/resources</directory><includes><include>**/*.*</include></includes></resource></resources></build></project>

2、yml文件(导入、导出共用代码)

spring:devtools:restart:enabled: true  #设置开启热部署additional-paths: src/main/java #重启目录exclude: WEB-INF/**freemarker:cache: false    #页面不加载缓存,修改即时生效servlet:multipart: #这里必须要加这配置,不然一百万条数据文件太大会拒绝导入max-request-size: 100MBmax-file-size: 100MB#数据库的配置,这里有个关键点,因为用的是mybatis-plus的saveBatch()方法批量插入数据库的,#所以这里必须加rewriteBatchedStatements=true,不然插入会非常的慢,#使用其它插入方式的可以忽略此配置datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://ip地址:端口号/数据库名称?rewriteBatchedStatements=trueusername: 用户名password: 密码

3、共用的代码文件(使用其他框架的可以忽略①②③④⑤操作

开始上代码咯

① 实体类对象TestExcel(导入、导出共用代码)

package com.bug.entity;import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;@Data
@TableName("test_excel")
public class TestExcel {/*** 可以通过index和name去匹配excel里的列* 注意name,index值不要重复*/@TableIdprivate String userId;@ExcelProperty(value = "姓名",index = 0)private String userName;@ExcelProperty(value = "年龄",index = 1)private String userAge;@ExcelProperty(value = "身份证号",index = 2)private String userCardid;}

② mapper层(导入、导出共用代码)

package com.bug.mapper.excel;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bug.entity.TestExcel;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface TestExcelMapper extends BaseMapper<TestExcel> {
}

③ service层(导入、导出共用代码)

package com.bug.service.excel;import com.baomidou.mybatisplus.extension.service.IService;
import com.bug.entity.TestExcel;public interface TestExcelService extends IService<TestExcel> {}

④ impl实现层(导入、导出共用代码)

package com.bug.service.excel.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bug.entity.TestExcel;
import com.bug.mapper.excel.TestExcelMapper;
import com.bug.service.excel.TestExcelService;
import org.springframework.stereotype.Service;@Service
public class TestExcelServiceImpl extends ServiceImpl<TestExcelMapper, TestExcel> implements TestExcelService {}

⑤ 分页工具(导入、导出共用代码)

package com.bug.config;import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class PageConfig {/*** 分页工具* @return PaginationInterceptor*/@Beanpublic PaginationInterceptor paginationInterceptor(){return new PaginationInterceptor();}}

⑥ EasyExcel的工具类(最主要的文件,如果使用的其它框架,可以忽略上面的代码,注释会尽量写的详细一些)

package com.bug.util.excel;import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson.JSON;
import com.bug.entity.TestExcel;
import com.bug.service.excel.TestExcelService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** 小bug* excel导入的工具类* 是不是很奇怪这里是实现的ReadListener接口而不是继承的AnalysisEventListener类* 因为源码里AnalysisEventListener类也是继承的ReadListener接口,何必多此一举呢*/
public class ExcelUpload implements ReadListener<TestExcel> {private TestExcelService testExcelService;/*** 注意这里是不能交给spring管理的,就是不能使用@Resource,或者@Autowired注入* 可以使用构造方法的方式获取你想要的对象* @param testExcelService testExcelService*/public ExcelUpload(TestExcelService testExcelService){this.testExcelService = testExcelService;}/*** 无参构造方法,不能省略*/public ExcelUpload(){}public static final Logger log = LoggerFactory.getLogger(ExcelUpload.class);private static final int count = 10000;//设置读取的条数,每次达到指定条数时就保存入数据库private List<TestExcel> testExcelListTure = new ArrayList<>();//校验正确的数据集合,数量达到设定值后插入数据库,然后再清空一直循环private List<TestExcel> testExcelListFalse = new ArrayList<>();//校验失败、保存数据库失败的数据集合,可以插入到一个失败数据表,或者显示在前端提醒用户哪些数据导入失败/*** 很明显,onException这个就是用来处理异常的,当其它侦听器出现异常时会触发此方法* @param e Exception* @param analysisContext analysisContext* Exception 默认是直接抛出异常的,要注意处理异常*/@Overridepublic void onException(Exception e, AnalysisContext analysisContext) {log.info("兄嘚,你的代码出现异常了!");e.printStackTrace();}/*** 获取excel的第一行head数据* @param map 数据map* @param analysisContext analysisContext*/@Overridepublic void invokeHead(Map<Integer, CellData> map, AnalysisContext analysisContext) {log.info("第一列:{} 第二列:{} 第三列:{}",map.get(0).getStringValue(),map.get(1).getStringValue(),map.get(2).getStringValue());}/*** 读取正文数据,一次只读取一行* @param testExcel 实体类对象* @param analysisContext analysisContext*/@Overridepublic void invoke(TestExcel testExcel, AnalysisContext analysisContext) {log.info("读取到一条数据:{}", JSON.toJSONString(testExcel));//因为是测试,这里只做一些简单的为空判断,正式的可以根据业务需求自己写校验条件if(testExcel == null){//对象为空直接跳出return;}else if(StringUtils.isBlank(testExcel.getUserName())){//判断名字是否为空testExcelListFalse.add(testExcel);//放入错误集合列表return;}else if(StringUtils.isBlank(testExcel.getUserCardid())){//判断身份证是否为空/*** 身份证号的判断,以前碰到过一个需求,就是不能和数据库已有的数据重复,数据库存在这个身份证号则表示数据已导入/不能再次导入* 我使用的方式是,先把那个表的”身份证号“字段全部查询出来加载到内存里,然后这里直接和查询出来的身份证号进行对比,存在的就不* 导入,并记录到错误集合列表标注为”重复导入“,不存在的才存入正确的集合列表,并把这个身份证号也存入内存,给后面的数据校验* 是否有重复的数据,这样所有的校验都在内存里进行,优点是:速度会很快、数据库压力也会很小,但是缺点也很明显:很占内存。* 不过通过测试:数据在百万级的,只查询身份证号的话,内存的占用是很少的,即使是微型服务器也能满足需求,而如果是千万级数据,相信* 能有这个数据量的,服务器也差不了,上亿数据量的还没处理过,以后有机会碰到了再进行测试吧,这里不进行身份证号相同的校验*/testExcelListFalse.add(testExcel);//放入错误集合列表return;}testExcelListTure.add(testExcel);//校验通过的方法正确集合列表if(count <= testExcelListTure.size()){//集合数据大于设定的数量时,提交数据库保存testExcelService.saveBatch(testExcelListTure);//批量存入数据库testExcelListTure = new ArrayList<>();//清空正确列表数据,再次循环}}/*** 额外单元格返回的数据,这个方法还没详细了解过,一直没用到过* @param cellExtra cellExtra对象* @param analysisContext analysisContext*/@Overridepublic void extra(CellExtra cellExtra, AnalysisContext analysisContext) {log.info("extra:{}",JSON.toJSONString(cellExtra));}/*** 当读取完所有数据后就会执行次方法* @param analysisContext analysisContext*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {log.info("兄嘚,所有数据读取完了哦!");//读取完excel后再次判断是否还要未存入数据库的数据if(testExcelListTure.size() > 0){testExcelService.saveBatch(testExcelListTure);//不为空,则存入数据库}//这里也可以处理错误列表,保存入错误列表数据库,或者显示到前端给用户查看}/*** 这个方法最坑,默认返回的是false,一定要记得改成true,为false时会只返回一条数据,* 意思是只会执行invokeHead方法* @param analysisContext analysisContext* @return 是否读取下一行*/@Overridepublic boolean hasNext(AnalysisContext analysisContext) {return true;}
}

4、使用for循环创建数据,并导出成excel文件(controller的依赖全放在这里了,后面不再重复写)

由于100万条数据量太多了,所以这里先使用代码生成100万条数据,再测试导入和导出

package com.bug.controller;import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bug.entity.TestExcel;
import com.bug.entity.WxConfig;
import com.bug.mapper.excel.TestExcelMapper;
import com.bug.service.excel.TestExcelService;
import com.bug.service.wxconfig.WxConfigService;
import com.bug.util.excel.ExcelUpload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;/*** EasyExcel 普通导入excel*/
@RequestMapping("/public")
@RestController
public class publicController {public static final Logger log = LoggerFactory.getLogger(publicController.class);@Resourceprivate WxConfigService wxConfigService;@Resourceprivate TestExcelService testExcelService;@Resourceprivate HttpServletRequest request;@Resourceprivate HttpServletResponse response;@Resourceprivate TestExcelMapper testExcelMapper;/*** 1、EasyExcel excel导出(for循环生成数据导出,百万级数据测试)* 相当于一次查询出一百万条数据,然后直接导出(此方式只适合少量数据,会很消耗内存)*/@GetMapping("/exportForExcel")public void exportForExcel() {log.info("for循环导出excel。。。");//需要导出的数据集合List<TestExcel> testExcelList = new ArrayList<>();long number = 100000000000000000L;for(int i=1; i<=1000000; i++){TestExcel testExcel = new TestExcel();testExcel.setUserAge(String.valueOf(i));testExcel.setUserCardid(String.valueOf(number+i));testExcel.setUserName("张三"+i);testExcelList.add(testExcel);}try {//下方使用了用户自己选择文件保存路径的方式,所以需要配请求参数,如果使用固定路径可忽略此代码String filename = URLEncoder.encode(System.currentTimeMillis()+".xlsx","UTF-8");response.setCharacterEncoding("UTF-8");response.setHeader("Content-disposition", "attachment; filename=" + filename);//设定输出文件头response.setContentType("application/x-xls");// 定义输出类型//不需要导出的字段userId,如果没有不需要导出的字段,可以忽略这个方法//只需要导入的字段,用includeColumnFiledNames()方法,写法是一样的Set<String> excludeColumnFiledNames = new HashSet<String>();excludeColumnFiledNames.add("userId");/*系统指定文件的输出路径String fileName = "D:/test/"+System.currentTimeMillis()+".xlsx";指定路径使用写法EasyExcel.write(fileName,TestExcel.class)EasyExcel.write()有很多种方法,其它方法可以直接查看源码*///这里采用用户自己选择文件保存路径的方式OutputStream out = response.getOutputStream();//开始导出,EasyExcel.write(out,TestExcel.class).excludeColumnFiledNames(excludeColumnFiledNames).sheet("测试模板").doWrite(testExcelList);}catch (Exception e){log.info("兄嘚,你代码又出错啦");e.printStackTrace();}}}

5、 excel导入

/*** 2、EasyExcel excel导入(百万级数据测试)* @return*/@PostMapping("/submitExcel")public void submitExcel(MultipartFile file){log.info("开始导入excel。。。");/*** EasyExcel.read有很多方法,也可以直接传入路径* String fileUrl = "D:/test/test.xlsx";*///创建readerExcelReader excelReader = null;try {excelReader = EasyExcel.read(file.getInputStream(), TestExcel.class, new ExcelUpload(testExcelService)).build();// 构建sheet,可以指定是第几个sheetReadSheet readSheet = EasyExcel.readSheet(0).build();// 读取sheetexcelReader.read(readSheet);}catch (Exception e){e.printStackTrace();}finally {if (excelReader != null) {//这里不能省略excelReader.finish();}}}

6、excel导出

    /*** 3、EasyExcel excel导出(分页查询数据导出,百万级数据测试)* 采用分页查询的方式导出excel,内存占用很少,数据量大的时候推荐使用此方式*/@GetMapping("/exportSqlExcel")public void exportSqlExcel() {log.info("sql分页导出excel。。。");//分页查询,每次查询量,这个插件最大只允许一次查500或者直接查全部,要想查更多的就只能去改源码了int pageNum = 500;ExcelWriter excelWriter = null;try {//下方使用了用户自己选择文件保存路径的方式,所以需要配请求参数,如果使用固定路径可忽略此代码String filename = URLEncoder.encode(System.currentTimeMillis()+".xlsx","UTF-8");response.setCharacterEncoding("UTF-8");response.setHeader("Content-disposition", "attachment; filename=" + filename);//设定输出文件头response.setContentType("application/x-xls");// 定义输出类型//不需要导出的字段userId,如果没有不需要导出的字段,可以忽略这个方法//只需要导入的字段,用includeColumnFiledNames()方法,写法是一样的//Set<String> excludeColumnFiledNames = new HashSet<String>();//excludeColumnFiledNames.add("userId");//这里采用用户自己选择文件保存路径的方式OutputStream out = response.getOutputStream();//这里其实就是把上面的方法分开写,写入同一个sheetexcelWriter = EasyExcel.write(out, TestExcel.class).build();WriteSheet writeSheet = EasyExcel.writerSheet("测试模板呀").build();//重点是这里的循环调用---分页查询,先查询出需要导出的总数long count = testExcelService.count();int num = (int)(count / pageNum) + 1;for (int i = 1; i < num; i++) {//分页查询Page<TestExcel> page = new Page<>(i,pageNum);IPage<TestExcel> testExcelIPage = testExcelService.page(page);List<TestExcel> testExcelList = testExcelIPage.getRecords();if(testExcelList.size() > 0){//导出excelWriter.write(testExcelList, writeSheet);}}}catch (Exception e){log.info("兄嘚,你代码又出错啦");e.printStackTrace();}finally {if (excelWriter != null) {excelWriter.finish();}}}

四、总结

EasyExcel本身的读写速度是非常快的,如上:导入100万条数据3个字段,只需要3-4分钟即可完成,for循环导出100万条只需要2分钟。

真正影响速度的其实是:你的批量插入方法和你的分页查询的速度,打个比方,就最上面的分页查询导出,循环对100万条分页查询,

一次只查500条,整个的导出需要15分钟左右,查询就用了12-13分钟左右。最后看看效果吧!

注:原文创作不易,转发的请带上此原文链接,并标明出处。

【EasyExcel导入、导出(百万数据量测试)粘贴即用】相关推荐

  1. 根据实体excel导入导出百万数据,可修改表头名称

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 表格导入导出实现效果展示 根据实体类导出模板 读取表格数据 导出数据为excel 进阶:修改表格导出的列头 controll ...

  2. Excel导入导出百万级数据

    Excel百万级数据导入导出方案 本文使用EasyExcel工作,导出格式XLSX 1.生成测试数据 这里用到的是MYSQL 5.7.31 创建表语句 CREATE TABLE `ACT_RESULT ...

  3. Java操作百万数据量Excel导入导出工具类(程序代码教程)

    Java操作百万数据量Excel导入导出工具类(程序代码教程): # 功能实现1.自定义导入数据格式,支持配置时间.小数点类型(支持单/多sheet)(2种方式:本地文件路径导入(只支持xls.xls ...

  4. springboot easyexcel导出百万数据优化

    说明 由于某些原因系统jvm内存最大只能给到512,但是要导出百万数据该如何实现呢?传统的一次性导出肯定是不行的 优化 Excel导出基于 springboot , easyexcel 依赖: < ...

  5. EasyExcel 低内存导出大数据量的Excel方案探索 50万行 50列 (附:实现代码)

    文章目录 1.前言 2.准备工作 3.导出测试 3.1.单次查询.全量导出 3.2. 多次查询,多个文件,单次写入 3.3.多次查询,多个文件,多次写入 3.4.多线程导出探索 3.5.文件打包成ZI ...

  6. Winform中导出Excel数据量百万级的处理办法-导出为csv文件

    场景 Winform中通过NPOI导出Excel的三种方式(HSSFWorkbook,XSSFWorkbook,SXSSFWorkbook)附代码下载: https://blog.csdn.net/B ...

  7. 【使用EasyExcel导入导出】

    使用EasyExcel导入导出 一,为什么要使用EasyExcel 1.1 EasyExcel与Poi的区别 Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个 ...

  8. 阿里EasyExcel导入导出

    阿里EasyExcel导入导出 前言 使用阿里提供的EasyExcel进行excel的导入导出简单,方便,快捷 ` 一.使用版本 <dependency><groupId>co ...

  9. MongoDB 教程六: MongoDB管理:数据导入导出,数据备份恢复及用户安全与认证

    视频地址:MongoDB 教程六: MongoDB管理:数据导入导出,数据备份恢复及用户安全与认证 MongoDB数据库备份与恢复 一.备份 先介绍下命令语法: mongodump -h dbhost ...

  10. Flink流式处理百万数据量CSV文件

    前言 最近公司让做一个'没有必要'的需求 需求针对的对象 这是同一个csv文件的不同展示形式 Excel展示形式 文本展示形式 这个csv文件中可能有数百万条数据 需求 将所有的异常数据检测出来 什么 ...

最新文章

  1. mxnet根据相似度进行人脸样本对图片清理
  2. IT团队之非正式沟通
  3. mysql 禁用查询缓存 query cache
  4. 二项式反演(非详细)
  5. 【Trie】【费用流】管道监控(loj 3026)
  6. ​【文末有福利】股票跨度——真实世界的算法
  7. python 遍历文件中的文件,文件名
  8. RSA加密、解密、签名、校验签名
  9. Android自动化测试之使用java调用monkeyrunner(补充篇)
  10. 卡内基梅隆 计算机音乐,音乐留学|卡内基梅隆音乐技术专业和申请要求详解!...
  11. ligerui php mysql_ligerui中3级联动的数据库例子
  12. Bean获取Spring容器
  13. pdf用什么软件打开
  14. ETCD数据库源码分析——etcdserver bootstrap初始化存储
  15. beta 值和 M 值: 衡量样本甲基化水平的金标准
  16. Esxi通过U盘启动
  17. Oracle 10g client(instantclient)环境配置
  18. 为什么说美团的天花板是美团自己?
  19. 视频监控SVAC安全控制简介
  20. 准备启动一个开源项目 - 技术族谱 - 先期利用Goolge云计算平台

热门文章

  1. 【Flutter实战静态页面】--在线点餐app(1)顶端栏
  2. 3月16日----3月20日二年级课程表
  3. 计算机毕业设计Android手机微博系统客户端app(源码+系统+mysql数据库+Lw文档)
  4. 移动硬盘无法访问如何解决
  5. OB0202 obsidian kanban插件使用
  6. 关闭Win10系统天气图标
  7. HyperLedger Fabric 查询机制
  8. 网络笔记(24) 云中网络:自己拿地成本高,购买公寓更灵活
  9. 【个人代码及思路】2018年9月CSP第一题:卖菜
  10. 华为云桌面,带你见识不一样的系统桌面