需求:测试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)
);
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文件
主要依赖是:
com.alibaba easyexcel2.2.10
全部依赖(根据自己的需求选择依赖,不用全部导入):
4.0.0 org.springframework.boot spring-boot-starter-parent2.4.3 com.bug bug0.0.1-SNAPSHOT my_springboot1 Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-devtoolsruntime true org.springframework.boot spring-boot-starter-testtest com.google.zxing core3.3.0 com.google.zxing javase3.3.3 org.testng testngRELEASE compile com.itextpdf itextpdf5.5.6 com.itextpdf itext-asian5.2.0 junit junit4.13 org.slf4j slf4j-api1.7.30 ch.qos.logback logback-classic1.2.3 junit junitcom.alibaba fastjson1.2.76 commons-io commons-io2.4 org.apache.commons commons-lang33.4 io.springfox springfox-swagger22.9.2 io.springfox springfox-swagger-ui2.9.2 org.springframework.boot spring-boot-starter-jdbc2.5.3 mysql mysql-connector-java5.1.38 com.baomidou mybatis-plus-boot-starter3.3.2 com.alibaba easyexcel2.2.10 org.projectlombok lombok1.18.12 provided org.springframework.boot spring-boot-maven-plugin2.4.3 src/main/java ***.*
2、yml文件(导入、导出共用代码)
spring:
devtools:
restart:
enabled: true #设置开启热部署
additional-paths: src/main/java #重启目录
exclude: WEB-INF
@TableId
private 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 {
}
③ service层(导入、导出共用代码)
package com.bug.service.excel;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bug.entity.TestExcel;
public interface TestExcelService extends IService {
}
④ 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 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 {
@Bean
public 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;
public class ExcelUpload implements ReadListener {
private 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 testExcelListTure = new ArrayList<>();//校验正确的数据集合,数量达到设定值后插入数据库,然后再清空一直循环
private List testExcelListFalse = new ArrayList<>();//校验失败、保存数据库失败的数据集合,可以插入到一个失败数据表,或者显示在前端提醒用户哪些数据导入失败
@Override
public void onException(Exception e, AnalysisContext analysisContext) {
log.info("兄嘚,你的代码出现异常了!");
e.printStackTrace();
}
@Override
public void invokeHead(Map map, AnalysisContext analysisContext) {
log.info("第一列:{} 第二列:{} 第三列:{}",map.get(0).getStringValue(),map.get(1).getStringValue(),map.get(2).getStringValue());
}
@Override
public 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<>();//清空正确列表数据,再次循环
}
}
@Override
public void extra(CellExtra cellExtra, AnalysisContext analysisContext) {
log.info("extra:{}",JSON.toJSonString(cellExtra));
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
log.info("兄嘚,所有数据读取完了哦!");
//读取完excel后再次判断是否还要未存入数据库的数据
if(testExcelListTure.size() > 0){
testExcelService.saveBatch(testExcelListTure);//不为空,则存入数据库
}
//这里也可以处理错误列表,保存入错误列表数据库,或者显示到前端给用户查看
}
@Override
public boolean hasNext(AnalysisContext analysisContext) {
return true;
}
}
4、使用for循环创建数据,并导出成excel文件(controller的依赖全放在这里了,后面不再重复写)
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{ }
③ service层(导入、导出共用代码)
package com.bug.service.excel;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bug.entity.TestExcel;
public interface TestExcelService extends IService {
}
④ 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 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 {
@Bean
public 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;
public class ExcelUpload implements ReadListener {
private 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 testExcelListTure = new ArrayList<>();//校验正确的数据集合,数量达到设定值后插入数据库,然后再清空一直循环
private List testExcelListFalse = new ArrayList<>();//校验失败、保存数据库失败的数据集合,可以插入到一个失败数据表,或者显示在前端提醒用户哪些数据导入失败
@Override
public void onException(Exception e, AnalysisContext analysisContext) {
log.info("兄嘚,你的代码出现异常了!");
e.printStackTrace();
}
@Override
public void invokeHead(Map map, AnalysisContext analysisContext) {
log.info("第一列:{} 第二列:{} 第三列:{}",map.get(0).getStringValue(),map.get(1).getStringValue(),map.get(2).getStringValue());
}
@Override
public 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<>();//清空正确列表数据,再次循环
}
}
@Override
public void extra(CellExtra cellExtra, AnalysisContext analysisContext) {
log.info("extra:{}",JSON.toJSonString(cellExtra));
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
log.info("兄嘚,所有数据读取完了哦!");
//读取完excel后再次判断是否还要未存入数据库的数据
if(testExcelListTure.size() > 0){
testExcelService.saveBatch(testExcelListTure);//不为空,则存入数据库
}
//这里也可以处理错误列表,保存入错误列表数据库,或者显示到前端给用户查看
}
@Override
public boolean hasNext(AnalysisContext analysisContext) {
return true;
}
}
4、使用for循环创建数据,并导出成excel文件(controller的依赖全放在这里了,后面不再重复写)
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 ServiceImplimplements 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 {
@Bean
public 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;
public class ExcelUpload implements ReadListener {
private 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 testExcelListTure = new ArrayList<>();//校验正确的数据集合,数量达到设定值后插入数据库,然后再清空一直循环
private List testExcelListFalse = new ArrayList<>();//校验失败、保存数据库失败的数据集合,可以插入到一个失败数据表,或者显示在前端提醒用户哪些数据导入失败
@Override
public void onException(Exception e, AnalysisContext analysisContext) {
log.info("兄嘚,你的代码出现异常了!");
e.printStackTrace();
}
@Override
public void invokeHead(Map map, AnalysisContext analysisContext) {
log.info("第一列:{} 第二列:{} 第三列:{}",map.get(0).getStringValue(),map.get(1).getStringValue(),map.get(2).getStringValue());
}
@Override
public 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<>();//清空正确列表数据,再次循环
}
}
@Override
public void extra(CellExtra cellExtra, AnalysisContext analysisContext) {
log.info("extra:{}",JSON.toJSonString(cellExtra));
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
log.info("兄嘚,所有数据读取完了哦!");
//读取完excel后再次判断是否还要未存入数据库的数据
if(testExcelListTure.size() > 0){
testExcelService.saveBatch(testExcelListTure);//不为空,则存入数据库
}
//这里也可以处理错误列表,保存入错误列表数据库,或者显示到前端给用户查看
}
@Override
public boolean hasNext(AnalysisContext analysisContext) {
return true;
}
}
4、使用for循环创建数据,并导出成excel文件(controller的依赖全放在这里了,后面不再重复写)
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; public class ExcelUpload implements ReadListener{ private 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 testExcelListTure = new ArrayList<>();//校验正确的数据集合,数量达到设定值后插入数据库,然后再清空一直循环 private List testExcelListFalse = new ArrayList<>();//校验失败、保存数据库失败的数据集合,可以插入到一个失败数据表,或者显示在前端提醒用户哪些数据导入失败 @Override public void onException(Exception e, AnalysisContext analysisContext) { log.info("兄嘚,你的代码出现异常了!"); e.printStackTrace(); } @Override public void invokeHead(Map map, AnalysisContext analysisContext) { log.info("第一列:{} 第二列:{} 第三列:{}",map.get(0).getStringValue(),map.get(1).getStringValue(),map.get(2).getStringValue()); } @Override public 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<>();//清空正确列表数据,再次循环 } } @Override public void extra(CellExtra cellExtra, AnalysisContext analysisContext) { log.info("extra:{}",JSON.toJSonString(cellExtra)); } @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { log.info("兄嘚,所有数据读取完了哦!"); //读取完excel后再次判断是否还要未存入数据库的数据 if(testExcelListTure.size() > 0){ testExcelService.saveBatch(testExcelListTure);//不为空,则存入数据库 } //这里也可以处理错误列表,保存入错误列表数据库,或者显示到前端给用户查看 } @Override public 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;
@RequestMapping("/public")
@RestController
public class publicController {
public static final Logger log = LoggerFactory.getLogger(publicController.class);
@Resource
private WxConfigService wxConfigService;
@Resource
private TestExcelService testExcelService;
@Resource
private HttpServletRequest request;
@Resource
private HttpServletResponse response;
@Resource
private TestExcelMapper testExcelMapper;
@GetMapping("/exportForExcel")
public void exportForExcel() {
log.info("for循环导出excel。。。");
//需要导出的数据集合
List 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 excludeColumnFiledNames = new HashSet();
excludeColumnFiledNames.add("userId");
//这里采用用户自己选择文件保存路径的方式
OutputStream out = response.getOutputStream();
//开始导出,
EasyExcel.write(out,TestExcel.class).excludeColumnFiledNames(excludeColumnFiledNames)
.sheet("测试模板")
.doWrite(testExcelList);
}catch (Exception e){
log.info("兄嘚,你代码又出错啦");
e.printStackTrace();
}
}
}
5、 excel导入
@PostMapping("/submitExcel")
public void submitExcel(MultipartFile file){
log.info("开始导入excel。。。");
//创建reader
ExcelReader excelReader = null;
try {
excelReader = EasyExcel.read(file.getInputStream(), TestExcel.class, new ExcelUpload(testExcelService)).build();
// 构建sheet,可以指定是第几个sheet
ReadSheet readSheet = EasyExcel.readSheet(0).build();
// 读取sheet
excelReader.read(readSheet);
}catch (Exception e){
e.printStackTrace();
}finally {
if (excelReader != null) {
//这里不能省略
excelReader.finish();
}
}
}
6、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 excludeColumnFiledNames = new HashSet();
//excludeColumnFiledNames.add("userId");
//这里采用用户自己选择文件保存路径的方式
OutputStream out = response.getOutputStream();
//这里其实就是把上面的方法分开写,写入同一个sheet
excelWriter = 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 page = new Page<>(i,pageNum);
IPage testExcelIPage = testExcelService.page(page);
List testExcelList = testExcelIPage.getRecords();
if(testExcelList.size() > 0){
//导出
excelWriter.write(testExcelList, writeSheet);
}
}
}catch (Exception e){
log.info("兄嘚,你代码又出错啦");
e.printStackTrace();
}finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
}
四、总结
@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 excludeColumnFiledNames = new HashSet();
//excludeColumnFiledNames.add("userId");
//这里采用用户自己选择文件保存路径的方式
OutputStream out = response.getOutputStream();
//这里其实就是把上面的方法分开写,写入同一个sheet
excelWriter = 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 page = new Page<>(i,pageNum);
IPage testExcelIPage = testExcelService.page(page);
List 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分钟左右。最后看看效果吧!
注:原文创作不易,转发的请带上此原文链接,并标明出处。



