将后端resources中的文件返给前端下载的方法

//后端

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: '文件下载失败' }
  }
}
相关推荐
程序员爱钓鱼11 分钟前
Rust Associated Type关联类型详解:为Trait定义内部类型
前端·后端·rust
zh_xuan1 小时前
个人主页左侧菜单支持分组,以及菜单显示和隐藏
前端·javascript·css
Emily156853598704 小时前
Emerson 1C31129G03 Analog Input Module
java·开发语言·前端·plc·emerson·1c31129g03·input module
To_OC9 小时前
面试被问了三回三栏布局,这次我终于把 BFC 那层窗户纸捅破了
前端·css·面试
To_OC9 小时前
啃完 TS 工具类型我发现:Pick 和 Omit 原来就是一层窗户纸
前端·面试·typescript
风月说与山鬼11 小时前
三、大括号语法
前端·react.js
kyriewen11 小时前
我把最常踩的8个CORS跨域报错整理了一遍——第8个去年还不存在
前端·javascript
Csvn12 小时前
🕰️ 闭包 + setTimeout 的 5 个经典陷阱:为什么定时器看到的永远不是最新的值?
前端
lilian23312 小时前
Harmony os 技术实战|拼豆制图27:用单字符编码承载 50 张 70×70 图纸
前端·数据库·华为·harmonyos