Spring文件POST(JSON)下载, restTemplate.execute大文件流处理

java下载接口

@PostMapping(value = "/download")
public void download(@RequestBody DownloadReq req, HttpServletRequest request, HttpServletResponse response) {
    
    // 省略..........

    String path = new File(path).getAbsolutePath() + File.separator + req.getFileName();
    File file = new File(path);
    if (!file.exists()) {
        LOGGER.info("file:{}", file.getAbsolutePath());
        LOGGER.info("下载文件不存在");
    }
    response.reset();
    response.setContentType("application/octet-stream");
    response.setCharacterEncoding("utf-8");
    response.setContentLength((int) file.length());
    String fileInfoHear = String.format("attachment;filename=%s", req.getFileName());
    response.addHeader("Content-Disposition", fileInfoHear);
    String origin = request.getHeader("Origin");
    response.addHeader("Access-Control-Allow-Origin", origin);
    response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
    response.addHeader("Access-Control-Allow-Headers", "Content-Type");
    response.addHeader("Access-Control-Allow-Credentials", "true");
    // 让浏览器能访问到其它响应头
    response.addHeader("Access-Control-Expose-Headers","Content-Disposition");


    try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));) {
        byte[] buff = new byte[1024];
        OutputStream os = response.getOutputStream();
        int i = 0;
        while ((i = bis.read(buff)) != -1) {
            os.write(buff, 0, i);
            os.flush();
        }
        LOGGER.info("file:{}, 下载成功", file.getAbsolutePath());
    } catch (IOException e) {
        LOGGER.error("异常", e);
    }
    // 只能返回null 或者方法是void, 否则会导致下载流关闭
}

java调用下载接口

public void download(DownloadReq req, String targetPath) {
    Map<String, Object> params = new HashMap<>();
    params.put("id", req.getId());

    Path targetPathO = Paths.get(targetPath);
    //定义请求头的接收类型
    RequestCallback requestCallback = request -> {
        request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
        // json参数
        request.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        request.getBody().write(JSON.toJSONString(params).getBytes());
    };

    ResponseExtractor<Void> responseExtractor = response -> {
        //对响应进行流式处理而不是将其全部加载到内存中
        Files.copy(response.getBody(), targetPathO, StandardCopyOption.REPLACE_EXISTING);
        return null;
    };
    // 省略代码.....
    restTemplate.execute(url, HttpMethod.POST, requestCallback, responseExtractor);
    log.info("下载文件:{}, 完成", req.getFileName());
}

前端调用下载接口

this.loading = true
axios({
  method: 'post',
  url: process.env.VUE_APP_BASE_API + '/download',
  data: {
      // json参数
      id: this.$data.id
  },
  responseType: 'blob',
  onDownloadProgress: (evt) => {
    // 对原生进度事件的处理, 会在浏览器下方弹出下载文件框
    this.setState({ progress: parseInt((evt.loaded / evt.total) * 100) });
  }
}).then(response => {
  let contentDisposition = response.headers['content-disposition'];  //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名;
  let filename = contentDisposition.split("filename=")[1];

  // 将二进制流转为blob
  let data = response.data ;
  const blob = new Blob([data], { type: 'application/octet-stream' })
  if (window.navigator.msSaveBlobOrOpenBlob) {
    // 兼容IE,window.navigator.msSaveBlob:以本地方式保存文件
    window.navigator.msSaveBlob(blob, decodeURI(filename))
  } else {
    // 创建新的URL并指向File对象或者Blob对象的地址
    const blobURL = window.URL.createObjectURL(blob)
    // 创建a标签,用于跳转至下载链接
    const tempLink = document.createElement('a')
    tempLink.style.display = 'none'
    tempLink.href = blobURL
    tempLink.setAttribute('download', decodeURI(filename))
    // 兼容:某些浏览器不支持HTML5的download属性
    if (typeof tempLink.download === 'undefined') {
      tempLink.setAttribute('target', '_blank')
    }
    // 挂载a标签
    document.body.appendChild(tempLink)
    tempLink.click()
    document.body.removeChild(tempLink)
    // 释放blob URL地址
    window.URL.revokeObjectURL(blobURL)
  }
}).finally(() => {
  this.loading = false
})

你可能感兴趣的:(springboot,java,java,spring,前端)