使用EasyExcel导出并压缩文件是一种高效且常见的解决方案,尤其适用于需要处理大量数据的场景。
1. 导出多个Excel文件并压缩成ZIP文件的基本流程
(1)数据准备:从数据库或其他数据源获取需要导出的数据,并将其存储在Java对象中(如List<YourEntity>
)。
(2)创建Excel文件:使用EasyExcel库将数据写入多个Excel文件。每个Excel文件可以对应一个Sheet表单。
(3)压缩文件:将生成的Excel文件打包成ZIP格式,通常通过ZipOutputStream
实现。
(4)响应输出:将压缩后的ZIP文件作为附件返回给客户端或上传到文件服务器(如腾讯云COS)。
2. 具体实现方法
(1)依赖引入
在项目的pom.xml
中添加EasyExcel依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>4.0.2</version>
</dependency>
该版本支持多种功能,包括流式写入、分批处理等。
(2)生成Excel文件
定义一个基础类(如UserData
),并使用EasyExcel写入数据:
import lombok.Data;
@Data
public class UserData {
private Integer id;
private String name;
private Integer age;
public UserData(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
}
定义一个对象,存放Excel文件名和文件流,压缩时使用
import lombok.Data;
import java.io.InputStream;
@Data
public class ZipDto {
public String name;
public InputStream inputStream;
public ZipDto(String name, InputStream inputStream) {
this.name = name;
this.inputStream = inputStream;
}
}
生成excel文件
public void exportUserData() {
List<ZipDto> zipDtoList = new ArrayList<>();
ZipDto zipDto = null;
int pageNumber = 0;
//每页查询数据库条数
int PER_PAGE_SIZE =10000;
com.alibaba.excel.ExcelWriter writer = null;
WriteSheet sheet = null;
try {
while (true) {
//分页从数据库加载业务数据
List<UserData> list =baseMapper.findUserDataForExport(pageNumber * PER_PAGE_SIZE, PER_PAGE_SIZE);
if (list.isEmpty()) {
break;
}
ByteArrayOutputStream oi = new ByteArrayOutputStream();
writer = EasyExcel.write(oi, UserData.class).build();
sheet = EasyExcel.writerSheet(0).build();
writer.write(list, sheet);
writer.finish();
zipDto = new ZipDto("用户信息" + DateUtil.now() + "-" + pageNumber + ".xlsx", new ByteArrayInputStream(oi.toByteArray()));
zipDtoList.add(zipDto);
if (list.size() < PER_PAGE_SIZE) {
break;
}
pageNumber++;
}
if (CollUtil.isNotEmpty(zipDtoList)) {
if (zipDtoList.size() == 1) {
zipDto = zipDtoList.get(0);
TencentCOSUtil.upLoad(zipDto.getInputstream(),
"userData_" + DateUtil.format(new Date(), "yyyy-MM"),"xlsx");
} else {
ByteArrayOutputStream oi = new ByteArrayOutputStream();
//将多个excel压缩为Zip文件
ZipUtils.zipListStream(zipDtoList, oi);
//如果集群部署,会导致文件下载失败,上传文件到云存储
TencentCOSUtil.upLoad(new ByteArrayInputStream(oi.toByteArray()),
"userData_" + DateUtil.format(new Date(), "yyyy-MM"), "zip");
}
}
} catch (Exception e) {
log.error("[exportUserData]导出失败:{}", e);
} finally {
if (writer != null) {
writer.close();
}
}
}
TencentCOSUtil.upload(InputStream inputStream, String path, String suffix) 是将文件上传到腾讯云文件服务器。后续单独写一篇介绍如何上传文件到腾讯云
(3)压缩为Zip文件
/**
* 将多个流转成zip文件输出
*
* @param listStream 文件流实体类对象
* @param out zip包的输出字节流
* @return
*/
public static boolean zipListStream(List<ZipDto> listStream, ByteArrayOutputStream out) {
boolean flag = false;
BufferedInputStream bis = null;
try (ZipOutputStream zos = new ZipOutputStream(out)) {
for (ZipDto zipDto : listStream) {
String fileName = zipDto.getName();
// 创建ZIP实体,并添加进压缩包
ZipEntry zipEntry = new ZipEntry(fileName);
zos.putNextEntry(zipEntry);
// 读取待压缩的文件并写进压缩包里
bis = new BufferedInputStream(zipDto.getInputStream());
byte[] buffer = new byte[1024];
int len = 0;
while ((len = bis.read(buffer)) != -1) {
zos.write(buffer, 0, len);
}
}
flag = true;
} catch (Exception e) {
log.error("[zipListStream]多个流转成zip文件异常",e);
} finally {
// 关闭流
try {
if (null != bis) {
bis.close();
}
if (null != out) {
out.close();
}
} catch (IOException e) {
log.error(e.getMessage());
}
}
return flag;
}
3. 注意事项
- 字符编码问题:在生成ZIP文件时,需确保文件名和内容的字符编码正确,避免中文乱码问题。