【问题标题】:Export file with custom name使用自定义名称导出文件
【发布时间】:2020-06-22 14:16:44
【问题描述】:

我想实现这个用于从 Spring BE 导出数据的代码示例。

@GetMapping("export/{ids}")
    public void export(HttpServletResponse response, @PathVariable List<Integer> ids) {

        List<Transactions> transactions = (List<Transactions>) transactionService.findAll(ids);
        List<TransactionExcelEntry> entries = transactions.stream().map(payment_transaction_mapper::toExcel).collect(Collectors.toList());

        List<String> headers = Arrays.asList("Id", "Name", "Type", "Created at");
        try {
            response.addHeader("Content-disposition", "attachment; filename=Transactions.xlsx");
            response.setContentType("application/vnd.ms-excel");
            new SimpleExporter().gridExport(headers, entries, "id, name", response.getOutputStream());
            response.flushBuffer();

        } catch (IOException ex) {
            LOG.debug("parsing of transactions failed");
        }
    }

导出按钮:

<button class="dropdown-item" (click)="export()">XLS</button>

导出功能:

export() {
    var newPagination = new Pagination();
    newPagination.size = this.pagination.size * this.pagination.total
    this.transactionService.search(newPagination, this.formGroup.value)
        .subscribe(result => {
            this.formGroup.enable();
            const query = result.content.map(t => t.id).join(',');
            this.transactionService.exportRows(query).subscribe(data => {
                const a = document.createElement('a');

                a.href = window.URL.createObjectURL(data);
                a.download = 'export.xls';
                a.click();
            });
        }, (error) => {
            this.formGroup.enable();
        });
  }

exportRows(query) {
    return this.http.get(`/api/transactions/export`, { responseType: 'blob' });
}

我想将文件名生成到 Java BE 中并从 Angular FE 下载。如何实现此功能?

【问题讨论】:

  • 澄清一下:您的意思是想让 Angular 自动下载名称为 Transactions.xlsx 的文件,因为它是后端设置的文件吗?
  • 正确。这个想法是 BE 应该使用当前时间戳设置名称。
  • Thierry 的回答有什么问题?

标签: angular spring angular7 angular8


【解决方案1】:

您可以通过访问响应标头并检索 Content-Disposition 来检索 Blob 的文件名。

为此,请稍微更改您的 HttpClient.get 呼叫,提供额外的选项 observe: 'response'

为了清楚起见,我们创建了一个专用的ExportResponse,只向我们的组件/或其他服务方法公开所需的数据:

export type ExportResponse = {
  blob: Blob,
  fileName: string
}

exportRows 检索 Response Headers

exportRows(query): ExportResponse {
  return this.http.get(`/api/transactions/export`, { 
    observe: 'response',
    responseType: 'blob' 
  }.pipe(
    map(response => {
      const contentDisposition = response.headers.get('content-disposition');
      return {
        blob: response.body,
        fileName: getContentDispositionFileName(contentDisposition)
      }
    })
  );
}

getContentDispositionFileName 方法负责从接收到的标头中提取文件名:

getContentDispositionFileName(contentDisposition: string) {
  let filename = 'default-file-name';

  var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
  var matches = filenameRegex.exec(contentDisposition);
  if (matches != null && matches[1]) {
    filename = matches[1].replace(/['"]/g, '');
  }

  return filename;
}

此 RegExp 模式来自 Winter Soldier's answer,并提取文件名的部分。

然后你可以在你的初始方法中使用ExportResponse

this.transactionService.exportRows(query).subscribe(response => {
  const a = document.createElement('a');
  a.href = window.URL.createObjectURL(response.blob);
  a.download = response.fileName;
  a.click();
});

重要提示

如果您启用了CORS,请注意允许您的后端发送并授权您的前端访问Content-Disposition 标头。

为此,请在您的回复中添加Access-Control-Expose-Headers: Content-Disposition

response.addHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);

【讨论】:

    【解决方案2】:

    如果您希望自动生成文件名,可以尝试以下方法

    export(filename) {
      this.transactionService.search(newPagination, this.formGroup.value)
            .subscribe(result => {
                this.formGroup.enable();
                const timeStamp: number = new Date().getTime();
                const query = result.content.map(t => t.id).join(',');
                this.transactionService.exportRows(query).subscribe(data => {
                    const a = document.createElement('a');
    
                    a.href = window.URL.createObjectURL(data);
                    a.download = `${fileName}-${timeStamp}.xls`;
                    a.click();
                });
            }, (error) => {
                this.formGroup.enable();
            });
    }
    

    点击按钮可以发送文件名,也可以通过服务调用从服务器获取文件名

    <button class="dropdown-item" (click)="export('Transaction')">XLS</button>
    

    【讨论】:

    • 谢谢,但我希望 BE 生成名称。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-17
    • 1970-01-01
    • 2022-01-18
    相关资源
    最近更新 更多