//后端
java
@GetMapping("getmoban")
// 下载模板
public AppResult<String> getmoban(HttpServletResponse response) {
// 尝试-with-resources确保流会被自动关闭
try (InputStream resourceAsStream = this.getClass().getResourceAsStream("/excelTemplates/importQualificationAbilityExcel.xlsx");
ServletOutputStream out = response.getOutputStream()) {
if (resourceAsStream == null) {
return AppResultBuilder.error(500, "模板文件不存在");
}
// 设置响应头信息
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=\"" +
URLEncoder.encode("导入excel模板.xlsx", "UTF-8") + "\"");
// 有些浏览器需要此头信息
response.setHeader("filename", URLEncoder.encode("导入excel模板.xlsx", "UTF-8"));
byte[] buffer = new byte[1024];
int len;
while ((len = resourceAsStream.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
out.flush(); // 确保所有数据都被写出
return AppResultBuilder.success("下载成功.");
} catch (UnsupportedEncodingException e) {
return AppResultBuilder.error(500, "编码错误: " + e.getMessage());
} catch (IOException e) {
return AppResultBuilder.error(500, "文件读写错误: " + e.getMessage());
}
}
前端
html
/**
* 二进制文件下载工具(优化版)
* @param binFile 二进制文件流(Blob对象)
* @param fileName 保存的文件名
* @param blobType MIME类型,默认为excel类型
*/
export const downloadBinaryFile = (
binFile: Blob,
fileName: string,
blobType = 'application/vnd.ms-excel',
) => {
// 确保传入的是Blob对象,避免类型错误
if (!(binFile instanceof Blob)) {
console.error('无效的二进制文件流')
return
}
// 创建URL对象
const url = window.URL.createObjectURL(new Blob([binFile], { type: blobType }))
const a = document.createElement('a')
a.href = url
a.download = fileName // 设置文件名(支持中文)
// 触发下载
document.body.appendChild(a)
a.click()
// 清理资源
document.body.removeChild(a)
window.URL.revokeObjectURL(url) // 释放URL对象,避免内存泄漏
}
html
import { downloadBinaryFile } from '@/utils/helpUtils.ts'
/**
* 下载模板文件(修改后的版本)
* @returns 无返回值,直接触发浏览器下载
*/
export const downloadimportFile = async () => {
try {
// 关键:设置responseType为blob,告知axios接收二进制流
const result: AxiosResponse<Blob> = await axios({
method: 'get',
url: '/api/job/qualification/getmoban',
responseType: 'blob', // 必须设置,否则会解析为JSON导致乱码
timeout: 60000, // 加大超时时间,避免大文件下载超时
})
// 从响应头获取文件名(后端设置的filename)
const contentDisposition = result.headers['content-disposition'] || ''
let fileName = '' // 默认文件名
// 解析响应头中的文件名(处理编码问题)
if (contentDisposition) {
const match = contentDisposition.match(/filename="(.*?)"/)
if (match && match[1]) {
fileName = decodeURIComponent(match[1]) // 解码URLEncoded的文件名
}
}
// 调用下载工具方法处理二进制流
downloadBinaryFile(result.data, fileName)
return { success: true } // 返回成功状态给调用方
} catch (error: any) {
if (isCustomAxiosError(error)) {
console.error('文件下载失败:', error.message)
} else {
console.error('文件下载异常:', error)
}
return { success: false, msg: '文件下载失败' }
}
}