项目需求,对于每一个人提交的文件,需要在后端配置统一的命名格式,批量导出压缩包。
文件是存储在分布式的mino里面的,主要是前后端的联调问题。还有过程中遇到的一些报错。
后端
使用了ZipOutputstream流。
从minio中拿去文件 通过minioClient.getObject 拿到client
in = minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName) // 替换为你的音频文件路径
.build()); //从mino中将数据文件流读取出来
@SneakyThrows
public void addFileToZip(String objectName, ZipOutputStream zipOut,String fileName) throws IOException {
InputStream in = null;
try {
in = minioClient.getObject(
GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName) // 替换为你的音频文件路径
.build());
//filename是统一编写的名称
zipOut.putNextEntry(new ZipEntry(fileName)); // 将文件名称添加到 ZIP
byte[] buffer = new byte[1024 * 10]; //创建一个字节数组 不断的往里面输入
int length;
while ((length = in.read(buffer)) > 0) {
zipOut.write(buffer, 0, length); // 写入 ZIP 输出流
zipOut.flush(); // 刷新 ZipOutputStream,确保数据被写入
}
zipOut.closeEntry(); // 关闭当前 ZIP 条目
} finally {
if (in != null) {
in.close(); // 关闭输入流
}
}
}
对于Controller类
不用void返回值,直接将文件流放入到response中去,前端是通过blob拿到的。
对于blob
JSON不好解析对应的二进制文本文件,文件上传服务器的响应式一个二进制文件,不是文本数据。
传入需要下载的ids和response
@PostMapping("/download-zip")
public void downloadZip(@RequestBody List<Integer> ids, HttpServletResponse response) {
taskSubService.exportFile(ids,response);
}
HttpServletResponse 直接输出到 HTTP 响应流中。Spring 框架的 HttpServletResponse 允许开发者直接操作响应流进行数据输出,而不需要通过返回值。
先拿到所有的文件地址。
ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())
需要理解这一段代码。
将数据压缩成 ZIP 格式,并将压缩后的数据直接通过 HTTP 响应流输出给客户端。
@SneakyThrows
@Override
public void exportFile(List<Integer> ids, HttpServletResponse response) {
List<TaskInfoVO> list = taskSubMapper.seletByIds(ids);
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"files.zip\"");
response.setContentType("application/zip");
response.setHeader(HttpHeaders.TRANSFER_ENCODING, "chunked"); // 添加 chunked encoding header
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
for (TaskInfoVO taskInfoVO : list) {
String path = taskInfoVO.getFilePath();
String objectName = path.substring(path.indexOf("file")); // 获取对象名称
System.out.println(objectName);
// 将文件添加到 ZIP 文件
String filename = generateCustomFileName(taskInfoVO);
minioTemplate.addFileToZip(objectName, zipOut, filename);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private String generateCustomFileName(TaskInfoVO taskInfoVO) {
String prefix = taskInfoVO.getFilePath().substring(taskInfoVO.getFilePath().lastIndexOf(".") + 1);
String filename = taskInfoVO.getTaskName() + "_" + taskInfoVO.getClassName() + "_" + taskInfoVO.getStudentName() + "_" + taskInfoVO.getStudentId() +
"." + prefix;
return filename;
}
常用的content-
response.setContentType("application/json");
response.setContentType("application/pdf");
response.setContentType("image/png");
response.setContentType("text/plain");
response.setContentType("text/html");
response.setContentType("video/mp4");
//二进制流
response.setContentType("application/octet-stream");
前端
responseType: 'blob', //设置参数的时候 这个比较重要 让后端返回对应的二进制流文件
const apiURL = 'http://localhost:8080'; // 替换为你的 API URL
import {getToken} from '@/utils/auth' //token的验证是放在 util/auth下面的
const handleExport = async () => {
try {
const response = await axios.post(`${apiURL}/tasksub/download-zip`, ids.value, {
responseType: 'blob',
headers: {
'Content-Type': 'application/json; application/octet-stream',
'Authorization': 'Bearer ' + getToken()// 添加 Bearer Token
},
});
const blob = new Blob([response.data], {type: 'application/zip'});
const fileName = 'aa'; //应该动态设置文件名
// 创建一个链接并下载文件
const a = document.createElement('a');
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
document.body.appendChild(a);
a.style.display = 'none'; // 隐藏链接
a.click(); // 触发下载
document.body.removeChild(a); // 下载后移除链接
window.URL.revokeObjectURL(url); // 释放 Blob URL
} catch (error) {
console.error('下载文件时出错:', error); // 错误处理
}
};