Spring + Angular - Как скачать файл сгенерированный сервером - PullRequest
1 голос
/ 28 мая 2020

У меня есть конечная точка на моем сервере, которая должна возвращать файл 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)
    );
  }

Это не идеально, потому что я не могу загрузить таким образом файл, сгенерированный сервером. В моем компоненте у меня есть метод экспорта JSON:

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 генерировал правильный тип ответа, при котором я мог бы получить как файл, так и имя файла с сервера.

1 Ответ

1 голос
/ 28 мая 2020

Попробуйте следующее:

 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);
   });
}
...