【问题标题】:Spring + Angular - How to download a server generated fileSpring + Angular - 如何下载服务器生成的文件
【发布时间】:2020-05-28 07:12:25
【问题描述】:

我的服务器上有一个端点,它应该返回一个动态生成的 json 文件。这是我写的:

    @GetMapping(value = "/{id}/json", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    @ApiOperation(value = "Animal data as a json file", authorizations = {@Authorization(value = "JWT")})
    public ResponseEntity<byte[]> getAnimalFile(@PathVariable("id") String id) throws JsonProcessingException {
       Animal animal = animalService.getAnimal(id);
       return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + animal.getId() + ".json").body(new ObjectMapper().writeValueAsBytes(animal));
    }

@ApiOperation 允许 swagger 在生成我的客户端库时包含此操作。 然而,这是 ng-swagger-gen 在 Angular 方面创建的:

  /**
   * @param id id
   * @return OK
   */
  getAnimalFileUsingGET(id: string): __Observable<string> {
    return this.getAnimalFileUsingGETResponse(id).pipe(
      __map(_r => _r.body as string)
    );
  }

这不是很理想,因为我无法通过这种方式下载服务器生成的文件。在我的组件中,我有一个 exportJSON 方法:

exportJSON(): void {
   this.animalService.getAnimalFileUsingGET(this.animal.id).subscribe(content => {
       console.log(content); // prints the json content but I don't have the filename
   });
}

我在 SO 上查看了其他答案,他们说使用 window.open(SERVER_ENDPOINT_HERE) 但这不起作用,因为我的端点使用身份验证 (JWT)。

有没有办法:

  • 让 ng-swagger-gen 意识到这是一个带有文件名的文件,并在我订阅它返回的 Observable 时提供给我
  • 还是绕过招摇并使用 Angular 使用服务器提供的文件名和身份验证来下载文件?

理想的解决方案是更改服务器端的某些内容,以便 swagger 生成正确的响应类型,我可以从服务器获取文件和文件名。

【问题讨论】:

    标签: angular spring swagger springfox


    【解决方案1】:

    尝试以下方法:

     getAnimalFileUsingGET(id: string | number): Observable<Blob> {
        return this.http.get(`/stats/export/${id}`, {responseType: 'blob'}); // Adjust your GET accordingly
      }
    

    另外,您需要安装 FileSaver.js

    npm i file-saver@1.3.2
    

    最后,像这样使用它:

     import { saveAs } from 'file-saver';
     .
     .
     .
     .
     .
    
     exportJSON(): void {
         this.animalService.getAnimalFileUsingGET(this.animal.id).subscribe((blob: Blob) => {
           saveAs(blob, 'export.json');
         });
     }
    

    编辑 1: 为了能够访问 Content-disposition 标头,您需要指示 Angular Http 客户端对响应进行一些更改。

      getAnimalFileUsingGET(id: string | number): Observable<HttpResponse<any>> {
        return this.http.get(`/stats/export/${id}`, {observe: 'response', responseType: 'json' })
      }
    

    然后你可以这样订阅:

    exportJSON(): void {
    this.animalService.getAnimalFileUsingGET(this.animal.id).subscribe((resp: HttpResponse<Blob>) => {
               console.log(resp.headers.get('content-disposition'));
               // Extract filename from header
               const filename = '';
               saveAs(resp.body, filename);
       });
    }
    

    【讨论】:

    • 感谢您的回答,很遗憾这并没有使用服务器提供的文件名
    • @Tecnogirl 由于您的端点返回一个 JSON 文件,您可以更改响应并包含文件名和数据。然后您可以像这样手动创建 Blob const blob = new Blob([JSON.stringify(jsonObject)], {type : 'application/json'});
    • 我不想用用于端点的东西“污染”动物实体。应该可以从 content-disposition 标头访问文件名
    • @Tecnogirl 您仍然需要找到一种方法从标题中提取文件名(可能是正则表达式?)但至少现在您应该可以访问它。
    • 您可以在后端的标头中传递文件名,并在您的打字稿代码中提取文件名,如下所示。HttpHeaders headers = new HttpHeaders(); headers.add("fileName", "testfile124.txt");
    猜你喜欢
    • 2018-02-09
    • 1970-01-01
    • 2016-10-23
    • 2018-05-26
    • 1970-01-01
    • 1970-01-01
    • 2022-10-14
    • 2019-12-21
    • 1970-01-01
    相关资源
    最近更新 更多