-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
JavaJavaJava
Description
导出操作流程
- 一对多数据导出到 Excel 内
- 数据关联的图片需要导出到文件夹
- 将 Excel 文件、文件夹打包成 Zip 压缩包并写入接口响应流
相关依赖
- Minio
- EasyPOI1
实现代码
导出 zip 压缩包结构
export.zip
├── export.xlsx # Excel 文件直接放在 ZIP 的根目录
└── file/
├── name1/
│ ├── image1.jpg # 商品1的图片文件
│ └── image2.jpg
└── name2/
├── image3.jpg # 商品2的图片文件
└── image4.jpg关键代码(文件流写入 Zip)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())
// create ZIP entry
ZipEntry zipEntry = new ZipEntry("export.xlsx");
zos.putNextEntry(zipEntry);
// Excel write to ZIP
zos.write(baos.toByteArray());
zos.closeEntry();具体实现
1. 导出 Excel 实体类
public class ExportData {
@Excel(name = "名称", needMerge = true)
private String name;
@ExcelCollection(name = "子数据")
private List<ExportDataChildren> children;
}2. 导出子数据类
public class ExportDataChildren {
@Excel(name = "名称")
private String name;
}3. 文件类
public class ExportFile {
// minio url
private String url;
}4. 业务代码
class ExportDataService {
public void exportDataZip(HttpServletResponse response) {
// get export data
List<ExportData> exportList = getExportData();
try (Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), ExportData.class, exportList);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
// Workbook write to ByteArrayOutputStream
workbook.write(baos);
// create ZIP entry
ZipEntry zipEntry = new ZipEntry("export.xlsx");
zos.putNextEntry(zipEntry);
// Excel write to ZIP
zos.write(baos.toByteArray());
zos.closeEntry();
// export file
exportList.forEach(exportData -> {
List<ExportFile> exportFileList = getExportFile();
exportFileList.forEach(exportFile -> {
try (InputStream inputStream = download(exportData.getUrl())) {
byte[] bytes = IoUtil.readBytes(inputStream);
String folderPath = "file/" + exportData.getName() + "/";
String name = FileUtil.getName(exportFile.getUrl());
ZipEntry entry = new ZipEntry(folderPath + name);
zos.putNextEntry(entry);
zos.write(bytes);
zos.closeEntry();
} catch (Exception e) {
log.error("export file error: {}", e.getMessage());
}
});
});
zos.finish();
response.flushBuffer();
} catch (Exception e) {
log.error("export zip error: {}", e.getMessage());
}
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=\"export.zip\"");
}
// get file InputStream
public InputStream download(String url) {
try {
return minioClient.getObject(
GetObjectArgs.builder()
.bucket(YOUR_BUCKET)
.object(url)
.build()
);
} catch (Exception e) {
log.error("download file error", e);
throw new BusinessException("文件下载异常");
}
}
public List<ExportData> getExportData() {
// 获取数据库数据
}
public List<ExportFile> getExportFile() {
// 获取数据库文件地址
}
}5. 代码实现流程图
flowchart TD
A[开始] --> B1[接收导出请求参数]
B1 --> B2[参数校验]
B2 --> |校验通过| B3[查询物料基础数据]
B2 --> |校验失败| E1[返回错误信息]
E1 --> H[结束]
B3 --> C[EasyPoi处理] & D[MinIO图片处理]
subgraph EasyPoi处理
C --> C1[创建ExportParams配置]
C1 --> C2[设置Excel样式和参数]
C2 --> C3[构建@Excel注解实体类]
C3 --> C4[准备导出数据List]
C4 --> C5[使用ExcelExportUtil.exportExcel]
C5 --> C6[获取Workbook字节数组流]
end
subgraph MinIO图片处理
D --> D1[创建MinIO客户端]
D1 --> D2[遍历物料图片数据]
D2 --> D3{是否有图片?}
D3 --> |是| D4[通过MinIO获取图片对象流]
D3 --> |否| D7[跳过处理]
D4 --> D5[创建以物料名称为路径的ZIP条目]
D5 --> D6[写入图片字节流到ZIP输出流]
D6 --> D8[检查数据完整性]
D7 --> D9[继续处理下一个]
D8 --> D9
end
C6 --> E[ZIP流处理]
D9 --> E
E --> F1[创建ByteArrayOutputStream]
F1 --> F2[创建ZipOutputStream]
F2 --> F3[写入Excel并创建entry]
F3 --> F4[写入图片并创建对应entry]
F4 --> F5[完成ZIP字节数组]
F5 --> G1[设置响应头ContentType等]
G1 --> G2[写入响应输出流]
G2 --> G3[关闭所有流资源]
G3 --> H[结束]
style A fill:#f9f,stroke:#333,stroke-width:2px
style H fill:#f9f,stroke:#333,stroke-width:2px
style E fill:#bbf,stroke:#333,stroke-width:2px
style F1 fill:#bbf,stroke:#333,stroke-width:2px
style F2 fill:#bbf,stroke:#333,stroke-width:2px
style F3 fill:#bbf,stroke:#333,stroke-width:2px
style F4 fill:#bbf,stroke:#333,stroke-width:2px
style B2 fill:#ffd,stroke:#333,stroke-width:2px
style D3 fill:#ffd,stroke:#333,stroke-width:2px
classDef note fill:#fff,stroke:#333,stroke-width:1px
class C1,C2,C3,C4,C5,D1,D4 note
Footnotes
Metadata
Metadata
Assignees
Labels
JavaJavaJava