官方网站
https://easyexcel.opensource.alibaba.com/docs/current/quickstart/read#最简单的读的excel示例
java代码:
package org.example.easyExc.controller;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.example.easyExc.entity.AsyncReq;
import org.example.easyExc.service.IAsyncReqService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @Author lzg
* @Create 2024/11/13 13:41
* Description:
* @Version 1.0
*/
@Slf4j
@ResponseBody
@Controller
public class EasyExcelController {
@Autowired
IAsyncReqService iAsyncReqService;
@GetMapping("down/{count}")
public void downExcel(HttpServletResponse response, @PathVariable("count") Integer count) throws InterruptedException, IOException {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试211", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
List<AsyncReq> itemData = data(count);
int skipIdx = 10000;
long startTime = System.currentTimeMillis();
// 这里 指定文件
try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), AsyncReq.class).build()) {
// 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面
for (int i = 0; i < 10; i++) {
// 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样
WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).build();
// 分页去数据库查询数据 这里可以去数据库查询每一页的数据
excelWriter.write(itemData, writeSheet);
}
}
System.out.println(System.currentTimeMillis() - startTime);
/**
*
* 10000
* 50000
* 100000 2.578
* 500000 13.148
* 1000000 28.511 10万条数据一个sheet,打开13秒
*/
}
/**
* 文件下载(失败了会返回一个有部分数据的Excel)
* <p>
* 1. 创建excel对应的实体对象 参照{@link AsyncReq}
* <p>
* 2. 设置返回的 参数
* <p>
* 3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
*/
@GetMapping("/download/{count}")
public void download(HttpServletResponse response, @PathVariable("count") Integer count) throws IOException {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
List<AsyncReq> itemData = data(count);
long startTime = System.currentTimeMillis();
EasyExcel.write(response.getOutputStream(), AsyncReq.class).sheet("模板985").doWrite(itemData);
System.out.println(System.currentTimeMillis() - startTime);
/**
* 10000 1.571
* 50000 2.954
* 100000 2.803
* 500000 12.924
* 1000000 26.340 100万条数据一个sheet,打开14秒
*
*/
}
private Collection<AsyncReq> data(int start, int end) {
// QueryChainWrapper<AsyncReq> query = iAsyncReqService.query();
QueryWrapper<AsyncReq> query = new QueryWrapper<>();
query.last("limit " + start + "," + end);
List<AsyncReq> list = iAsyncReqService.list(query);
log.info("db数量:{}", list.size());
return list;
}
private List<AsyncReq> data(int count) {
LocalDateTime now = LocalDateTime.now();
//('234324324', 'mcpdng', 'async_type', 'routing_key', 'exchange', 'org.example.easyExc.entity.AsyncReq', '{}', 'init', '1', '1', '1', '{}', '2024-11-13 13:56:01','2024-11-13 13:56:01', '0');
AsyncReq asyncReq = new AsyncReq().setAsyncId("121233").setAsyncType("async_type").setRoutingKey("routing_key")
.setExchange("exchange")
.setRoutingKey("routing_key")
.setParamClassName("org.example.easyExc.entity.AsyncReq")
.setParamJsonDetail("{}")
.setExecStatus("1")
.setUpdateTime(now)
.setCreateTime(now)
.setExecCount(1)
.setSendCount(1)
.setExtInfo("{}");
List<AsyncReq> list = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
list.add(asyncReq);
}
log.info("db数量:{}", list.size());
return list;
}
// /**
// * 文件上传
// * <p>1. 创建excel对应的实体对象 参照{@link UploadData}
// * <p>2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener}
// * <p>3. 直接读即可
// */
// @PostMapping("upload")
// @ResponseBody
// public String upload(MultipartFile file) throws IOException {
// EasyExcel.read(file.getInputStream(), AsyncReq.class, new UploadDataListener(uploadDAO)).sheet().doRead();
// return "success";
// }
}
小结:
使用了easyexcl 在排除了db的耗时之后, 多sheet页(10个sheet页)和单sheet页, 插入1百万(26s)/50万(12s)/10万(2s)/10万以下(2s)条数据的时间很相似; 几乎无差别, 影响速度的往往是db或是网络
百万条数据下(14s), 多sheet页(10页)和单sheet页, 在打开速度上很相似; 几乎无差别
easyexcl不允许多线程操作多个sheet页;他本身在插入数据表时已经用了多线程,如果多个sheet页再同时开可能会出问题;
可能也是这个原因导致多sheet页下速度没差别