vue下载文件并重命名

在Vue项目中,为了实现文件上传下载功能,遇到上传文件后使用随机数命名的问题。为解决这个问题,作者增加了文件重命名的特性。最初尝试在前端直接处理文件流进行下载,但出现了文件乱码问题。最终,作者选择通过后台解析文件流,前端接收来避免文件损坏,实现了正常下载。以下是前后端关键代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

vue的项目,需要做一个文件上传下载的功能。上传是OK的,然鹅因为上传到minio的时候,使用了随机数命名,导致文件名称就变成了一大串字符。被客户驳回来了。那好吧,就加一个重命名功能好了。
不过这个项目好奇怪,正常的后台解析文件流,前端下载的方案,下载下来文件都会变成乱码,怎么改都不行,最后,参考了JavaScript 实现文件下载并重命名 直接在vue端实现了文件的转为blob并下载。 代码如下:

    download(downloadUrl,downloadFileName ) {
        this.getBlob(downloadUrl).then(blob => {
            this.saveAs(blob, downloadFileName + ".pdf");
        });
    },
    
  getBlob(url) {
        return new Promise(resolve => {
            const xhr = new XMLHttpRequest();

            xhr.open('GET', url, true);
            xhr.responseType = 'blob';
            xhr.onload = () => {
                if (xhr.status === 200) {
                    resolve(xhr.response);
                }
            };

            xhr.send();
        });
    },

    saveAs(blob, filename) {
        if (window.navigator.msSaveOrOpenBlob) {
            navigator.msSaveBlob(blob, filename);
        } else {
            const link = document.createElement('a');
            const body = document.querySelector('body');

            let binaryData = [];
            binaryData.push(blob);
            link.href = window.URL.createObjectURL(new Blob(binaryData));
            link.download = filename;

            // fix Firefox
            link.style.display = 'none';
            body.appendChild(link);

            link.click();
            body.removeChild(link);

            window.URL.revokeObjectURL(link.href);
        }
    },

直接调用 download(下载地址,重命名的文件名) 即可

==============================================
20210926补充
一个严重的问题,本项目中,这样写,会造成下载的PDF文件损坏,无法打开。因此,最后还是采用了后台解析文件流,传到前端进行下载的方案。具体代码如下:
后台代码:

  /**
   * 下载附件
   * @param response
   * @param fileName
   */
  @GetMapping(value = "/downloadAttachment")
  public ResponseEntity<?>  downloadAttachment(final HttpServletResponse response, @RequestParam("fileName") String fileName) {
    InputStream inputStream = null;
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try {

      // 获取文件信息
      ObjectStat objectStat = template.getObjectInfo(bucketName, fileName);
      // 设置响应头
      response.setHeader("content-type", objectStat.contentType());
      response.setContentType(objectStat.contentType());
      // 获取文件输入流
      inputStream = template.getObject(bucketName, fileName);
      
      outputStream = this.readInpurStream(inputStream);

      ByteArrayResource resource = new ByteArrayResource(outputStream.toByteArray());
      return ResponseEntity.ok()
        .contentType(MediaType.APPLICATION_OCTET_STREAM)
        .header(HttpHeaders.CONTENT_DISPOSITION, String.format("attachment; filename=%s", URLEncoder.encode(fileName+".pdf", "UTF-8")))
        .body(resource);
    } catch (Exception e) {
      log.error("导出附件失败:",e);
      return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("下载文件出现异常");
    }
  }

  /**
   * 将input流转化为ByteArrayOutputStream
   * @param input
   * @return
   * @throws Exception
   */
  public ByteArrayOutputStream readInpurStream(InputStream input) throws Exception{
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int len;
    try {
      while ((len = input.read(buffer)) > -1) {
        baos.write(buffer, 0, len);
      }
      baos.flush();
    } catch (IOException e) {
      throw new Exception("Illegal flow.");
    } finally {
      try {
        input.close();
      } catch (IOException e) {
        log.error("file stream shutdown failed.");
      }
    }
    return baos;
  }

前端代码:

download: function () {

    let params=Object.assign({
        fileName: this.fileAppendix
    });

    downloadFile(params).then(res => {
        exportPdf(res.data, this.downloadFileName);
    })
},
            
export function downloadFile(query) {
  return fetchRequest('/downloadAttachment',{
    method: 'get',
    params: query
  })
}

// 导出为pdf
export const exportPdf = (res, name) => {
  const blob = new Blob([res]);
  let fileName = name ? name + ".pdf" : Date.parse(new Date()) + ".pdf";
  if ("download" in document.createElement("a")) {
    // 非IE下载
    const elink = document.createElement("a");
    elink.download = fileName;
    elink.style.display = "none";
    elink.href = URL.createObjectURL(blob);
    document.body.appendChild(elink);
    elink.click();
    URL.revokeObjectURL(elink.href); // 释放URL 对象
    document.body.removeChild(elink);
  } else {
    // IE10+下载
    navigator.msSaveBlob(blob, fileName);
  }
};

export default function fetchRequest(url, options) {
  let content = {
    headers: {
      Authorization: `bearer ${getToken()}`,
      "Content-type": "application/json",
    },
    method: options.method,
  };
  let pathUrl = url;
  if (options.method === "get") {
    pathUrl = pathUrl + formatUrl(options.params);
  } else if (options.method === "post") {
    content.body = JSON.stringify(options.data);
  }
  return fetch(pathUrl, content)
    .then(checkStatus)
    .then(parseBlob)
    .then((data) => ({ data }))
    .catch((err) => ({ err }));
}

不过这么写虽然可以解决问题,但是代码就要写的比较多,回头有空再看看有没有更好的写法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值