【EasyExcel导入、导出(百万数据量测试)粘贴即用】
需求:测试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导入、导出(百万数据量测试)粘贴即用】相关推荐
- 根据实体excel导入导出百万数据,可修改表头名称
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 表格导入导出实现效果展示 根据实体类导出模板 读取表格数据 导出数据为excel 进阶:修改表格导出的列头 controll ...
- Excel导入导出百万级数据
Excel百万级数据导入导出方案 本文使用EasyExcel工作,导出格式XLSX 1.生成测试数据 这里用到的是MYSQL 5.7.31 创建表语句 CREATE TABLE `ACT_RESULT ...
- Java操作百万数据量Excel导入导出工具类(程序代码教程)
Java操作百万数据量Excel导入导出工具类(程序代码教程): # 功能实现1.自定义导入数据格式,支持配置时间.小数点类型(支持单/多sheet)(2种方式:本地文件路径导入(只支持xls.xls ...
- springboot easyexcel导出百万数据优化
说明 由于某些原因系统jvm内存最大只能给到512,但是要导出百万数据该如何实现呢?传统的一次性导出肯定是不行的 优化 Excel导出基于 springboot , easyexcel 依赖: < ...
- EasyExcel 低内存导出大数据量的Excel方案探索 50万行 50列 (附:实现代码)
文章目录 1.前言 2.准备工作 3.导出测试 3.1.单次查询.全量导出 3.2. 多次查询,多个文件,单次写入 3.3.多次查询,多个文件,多次写入 3.4.多线程导出探索 3.5.文件打包成ZI ...
- Winform中导出Excel数据量百万级的处理办法-导出为csv文件
场景 Winform中通过NPOI导出Excel的三种方式(HSSFWorkbook,XSSFWorkbook,SXSSFWorkbook)附代码下载: https://blog.csdn.net/B ...
- 【使用EasyExcel导入导出】
使用EasyExcel导入导出 一,为什么要使用EasyExcel 1.1 EasyExcel与Poi的区别 Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个 ...
- 阿里EasyExcel导入导出
阿里EasyExcel导入导出 前言 使用阿里提供的EasyExcel进行excel的导入导出简单,方便,快捷 ` 一.使用版本 <dependency><groupId>co ...
- MongoDB 教程六: MongoDB管理:数据导入导出,数据备份恢复及用户安全与认证
视频地址:MongoDB 教程六: MongoDB管理:数据导入导出,数据备份恢复及用户安全与认证 MongoDB数据库备份与恢复 一.备份 先介绍下命令语法: mongodump -h dbhost ...
- Flink流式处理百万数据量CSV文件
前言 最近公司让做一个'没有必要'的需求 需求针对的对象 这是同一个csv文件的不同展示形式 Excel展示形式 文本展示形式 这个csv文件中可能有数百万条数据 需求 将所有的异常数据检测出来 什么 ...
最新文章
- mxnet根据相似度进行人脸样本对图片清理
- IT团队之非正式沟通
- mysql 禁用查询缓存 query cache
- 二项式反演(非详细)
- 【Trie】【费用流】管道监控(loj 3026)
- ​【文末有福利】股票跨度——真实世界的算法
- python 遍历文件中的文件,文件名
- RSA加密、解密、签名、校验签名
- Android自动化测试之使用java调用monkeyrunner(补充篇)
- 卡内基梅隆 计算机音乐,音乐留学|卡内基梅隆音乐技术专业和申请要求详解!...
- ligerui php mysql_ligerui中3级联动的数据库例子
- Bean获取Spring容器
- pdf用什么软件打开
- ETCD数据库源码分析——etcdserver bootstrap初始化存储
- beta 值和 M 值: 衡量样本甲基化水平的金标准
- Esxi通过U盘启动
- Oracle 10g client(instantclient)环境配置
- 为什么说美团的天花板是美团自己?
- 视频监控SVAC安全控制简介
- 准备启动一个开源项目 - 技术族谱 - 先期利用Goolge云计算平台