vue+springboot实现文件模版下载

92 阅读2分钟

最近再做个功能,需要实现excel模版下载。在这里记录一下。

后端java实现

@PostMapping("/download")
public ResponseEntity<?> downloadTemplate(@RequestBody Map<String,String> templateTypeMap) {
        String fileName = DownloadTemplateEnum.getTemplateNameByType(templateTypeMap.getOrDefault("templateType", null));
        try {
            // 创建文件资源
            String filePath = "excelTemplate/" + fileName;
            Resource resource = new ClassPathResource(filePath);
            // 检查文件是否存在
            if (!resource.exists()) {
                return ResponseEntity.status(HttpStatus.NOT_FOUND)
                        .body("文件不存在: " + fileName);
            }

            // 设置响应头
            HttpHeaders headers = new HttpHeaders();
            String encodedFileName = URLEncoder.encode(resource.getFilename(), StandardCharsets.UTF_8.toString());
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + encodedFileName + ".xlsx");

            // 返回文件
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(resource);
        } catch (IOException e) {
            // 处理其他异常
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("发生错误: " + e.getMessage());
        }
    }
  • 这里使用了ClassPathResource用于读取resources目录下的模版文件。
  • 使用ResponseEntity作为响应数据。如果在前端定义的有自己的封装响应数据结果,比如code和data,需要在这个结构中增加status。因为ResponseEntity响应的状态码在status中
  declare interface IResponse<T = any> {
    status: number
    code: number
    data: T extends any ? T : T & any
  }

提示: 在使用ClassPathResource判断文件是否存在是,如果遇到明明文件已有,但是判断仍是false。检查编译后的target/classes/excelTemplate文件下是否有对应文件。很有可能是编译的时候没有把文件编译过去,重新编译或者重启idea或自己手动复制过去都可以解决

前端js实现

const handleDownload = async () => {
  const data = { templateType: 'xxx' }
  const response = await downloadTemplateApi(data, 'blob')
  // 检查响应是否成功
  if (response.status === 200) {
    // 创建一个隐藏的 a 标签来触发下载
    const link = document.createElement('a')
    link.href = URL.createObjectURL(response.data)
    link.download = '导入品牌模版.xlsx' // 设置下载的文件名
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    importManufacturerDialogVisible.value = !importManufacturerDialogVisible.value
  } else {
    ElMessage.error('下载失败')
  }
}
  • 传入参数的时候需要指定responseType为blob类型
  • 通过创建临时隐藏标签

扩展

前端常见的返回类型如下:

  1. 'arraybuffer' :

    • 二进制数据的数组形式。
    • 适用于需要处理二进制数据的情况,例如图像、音频或视频文件。
    • 返回值是一个 ArrayBuffer 对象。
  2. 'blob' :

    • 二进制大对象(Binary Large Object)。
    • 适用于需要处理二进制数据的情况,但与 arraybuffer 不同的是,blob 可以表示任何类型的二进制数据,并且可以被浏览器直接使用(例如显示为图片)。
    • 返回值是一个 Blob 对象。
  3. 'document' :

    • 适用于需要将响应解析为 HTML 或 XML 文档的情况。
    • 返回值是一个 Document 对象,可以使用 DOM 操作方法进行处理。
    • 通常用于处理 XML 数据或动态生成的 HTML 内容。
  4. 'json' :

    • 将响应体解析为 JSON 格式。
    • 适用于返回 JSON 数据的 API。
    • 返回值是一个 JavaScript 对象。
  5. 'text' :

    • 将响应体作为纯文本字符串处理。
    • 适用于返回纯文本数据的 API。
    • 返回值是一个字符串。
  6. 'stream' :

    • 流式处理响应数据。
    • 适用于处理大文件或需要逐步处理数据的情况。
    • 返回值是一个可读流(ReadableStream)。
  7. 'formdata' :

    • 将响应体解析为 FormData 对象。
    • 适用于处理表单数据。
    • 返回值是一个 FormData 对象,可以方便地访问和操作表单字段。

参考