前端采用的是vue和axios
后端关键点:
response.setHeader("Content-Disposition", "attachment;filename=" + new String(objectName.getBytes(), "ISO-8859-1"));
response.setContentType("application/octet-stream");
后端全部代码:
/**
* 下载文件
//objectName是文件全名称,如"图片.png"
*/
@GetMapping("/downLoad")
public void downLoad(@RequestParam("key") String objectName,
HttpServletResponse response) throws UnsupportedEncodingException {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
//通知浏览器以附件形式下载,(必要的配置!!!!!)
response.setHeader("Content-Disposition",
"attachment;filename=" + new String(objectName.getBytes(),
"ISO-8859-1"));
response.setContentType("application/octet-stream");
try {
// 调用ossClient.getObject返回一个OSSObject实例,该实例包含文件内容及文件元数据。
OSSObject ossObject = ossClient.getObject(bucketName, objectName);
// 调用ossObject.getObjectContent获取文件输入流,可读取此输入流获取其内容。
InputStream fis = ossObject.getObjectContent();
//获取缓冲输出流
OutputStream fos = response.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(fos);
//开始发送数据
byte[] buffer = new byte[1024];
int length = 0;
while ((length = fis.read(buffer)) != -1) {
bos.write(buffer, 0, length);
}
if (bos != null) {
bos.flush();
bos.close();
}
if (fis != null) {
fis.close();
}
} catch (OSSException oe) {
//..............处理错误
} catch (ClientException ce) {
//..............处理错误
} catch (IOException ex) {
//..............处理错误
} finally {
//关闭资源
if (ossClient != null) {
ossClient.shutdown();
}
}
}
前端关键点:
axios的请求中
timeout: "0",
//我的项目中,如果不把超时时间设置成无限,会导致文件没下载不完全
responseType: 'blob'
//返回类型设置成流传输
参考axios文档:{
// `responseType` 表示浏览器将要响应的数据类型
// 选项包括: 'arraybuffer', 'document', 'json', 'text', 'stream'
// 浏览器专属:'blob'
responseType: 'json', // 默认值
}
前端请求完整代码: (用的是Elemnet Plus)
const handleDownLoad = (index: number, row: File) => {
request({
url: "/downLoad",
method: "GET",
timeout: "0",
params: {
key: row.key//row.key是文件的全名称
},
responseType: 'blob'//必要的设置
}).then((res) => {
/**
以下代码是为了让浏览器下载器中显示文件下载完成
不太清楚原理...
*/
let blob = new Blob([res], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;"});
// 为blob设置文件类型,这里以.xlsx为例
let url = window.URL.createObjectURL(blob);
// 创建一个临时的url指向blob对象
let a = document.createElement("a");
a.href = url;
a.download = row.key;
a.click();
// 释放这个临时的对象url
window.URL.revokeObjectURL(url);
})
}
<el-table :data="files" style="width: 100%" v-loading="loading">
<el-table-column label="上传时间" width="380">
<template #default="scope">
<div style="display: flex; align-items: center">
<el-icon>
<timer/>
</el-icon>
<span style="margin-left: 10px">{{ scope.row.modifiedTime }}</span>
</div>
</template>
</el-table-column>
<el-table-column label="文件名" width="380">
<template #default="scope">
<div style="display: flex; align-items: center">
<span style="margin-left: 10px">{{ scope.row.key }}</span>
</div>
</template>
</el-table-column>
<el-table-column label="文件大小" width="380">
<template #default="scope">
<div style="display: flex; align-items: center">
<span style="margin-left: 10px">{{ (scope.row.size / (1024 * 1024)).toFixed(2) }}MB</span>
</div>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button size="small" type="primary" @click="handleView(scope.$index, scope.row)">在线预览</el-button>
<el-button size="small" type="success" @click="handleDownLoad(scope.$index, scope.row)"
element-loading-text="Loading...">下载
</el-button>
<el-button
size="small"
type="danger"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
成功截图: