【问题标题】:How to download xls file via spring boot & Angular 9如何通过 Spring Boot 和 Angular 9 下载 xls 文件
【发布时间】:2021-01-27 14:21:15
【问题描述】:

(Jhipster,前端 Angular 9 和后端 spring-boot)

我的应用会生成 xls 报告。 该报告是用 Apache Poi 完成的,并在本地复制。

现在我正在尝试将文件下载到客户端,但我不知道如何。

我想在下载完成后删除文件。 这是一个 post 方法,因为我发送报告的数据。

你有什么想法吗?

这是我的控制器:

public void createFullReport(@Valid @RequestBody ReportDTO report, HttpServletResponse response) throws IOException {
    log.debug("REPORTDTO : {}", report);

    File outputFile = this.reportService.makeFullReport(report);

    log.debug("FILE EXIST:{}", outputFile.exists());
    log.debug("IS FILE:{}", outputFile.isFile());
    log.debug("FILE NAME:{}", outputFile.getName());

    FileInputStream stream = new FileInputStream(outputFile);
    response.setContentType("application/vnd.ms-excel");
    response.setHeader("Content-disposition", "attachment; filename=" + outputFile.getName());
    }

我的服务:

create(report: IReport): any {
    console.log(report);
    return this.http.post<any>(this.resourceUrl, report, { observe: 'response' });
  }

我的组件:

this.reportService.create(this.report).subscribe((response: any) => {
  console.log(response);
  var blob = new Blob([response._body], { type: 'application/vnd.ms-excel' });
});

编辑

控制器:

@PostMapping("/report")
@PreAuthorize(
    "hasAnyAuthority(\"" +
    AuthoritiesConstants.ADMIN +
    "\"+\"," +
    AuthoritiesConstants.CUSTOMER_ADMIN +
    "\"+\"," +
    AuthoritiesConstants.INSPECTOR +
    "\")"
)
public ResponseEntity  createFullReport(@Valid @RequestBody ReportDTO report, HttpServletResponse response) throws IOException {
    log.debug("REPORTDTO : {}", report);
    XSSFWorkbook wb = (XSSFWorkbook) this.reportService.makeFullReport(report);
    response.setHeader("Content-Disposition","attachment; filename=\"timesheet.xlsx\"");
    writeToOutputStream(response,wb);
    return ResponseEntity.ok().build();
}

private void writeToOutputStream(HttpServletResponse response,XSSFWorkbook wb){

    ServletOutputStream out ;
    try {
        out = response.getOutputStream();
        wb.write(out);
        wb.close();
        out.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

角度服务:

  create(report: IReport): any {
    console.log(report);
    let HTTPOptions:Object = {

      headers: new HttpHeaders({
          'Content-Type': 'application/json'
      }),
      responseType: 'blob'
   }
    return this.http.post<any>(this.resourceUrl, report,HTTPOptions);
  }

【问题讨论】:

    标签: java angular spring-boot jhipster


    【解决方案1】:

    我想在下载完成后删除文件。这是一个帖子 方法,因为我发送报告的数据。

    那会很复杂,你不需要这么复杂。

    尽量不要将您的 xls 文件保存在某处。只需使用您的 apache poi 作为工作簿创建它。然后将该工作簿的内容作为字节数组直接写入控制器中。

    这样,您将实现动态创建和交付 xls 文件,而无需同步后端和前端以便稍后将其删除。

     @PostMapping()
     public ResponseEntity createAndDeliverFile(HttpServletResponse response){
            
            response.setHeader("Content-Disposition","attachment; filename=\"myFileName.xlsx\"");
    
            XSSFWorkbook wb = fileWriterService.createAndReturnFile();
    
            writeToOutputStream(response,wb);
    
            return ResponseEntity.ok().build();
        }
    
    
       public void writeToOutputStream(HttpServletResponse response,XSSFWorkbook wb){
    
        ServletOutputStream out ;
        try {
            out = response.getOutputStream();
            wb.write(out);
            wb.close();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    
    }
    

    至于下载文件,您的代码似乎没有错,但是如果它带来任何类型的错误,您可能需要稍微调整一些东西。准备好后只需添加 FileSaver 即可下载文件

     My component:
    
        import * as FileSaver from 'file-saver';
        
        this.reportService.create(this.report).subscribe((response: any) => {
          console.log(response);
          var blob = new Blob([response._body], { type: 'application/vnd.ms-excel'});
          FileSaver.saveAs(blob, 'filename' + '.xlsx;);
        });
    

    在 cmets 之后编辑(看来当数据来自 xlsx 时转换为 Blob 需要格外小心!)

    create(report: IReport): any {
        console.log(report);
        let HTTPOptions:Object = {
    
          headers: new HttpHeaders({
              'Content-Type': 'application/json'
          }),
          responseType: 'blob' as 'json'   <----------
       }
        return this.http.post<any>(this.resourceUrl, report,HTTPOptions);
      }
    

    我的组件:

        import * as FileSaver from 'file-saver';
        
        this.reportService.create(this.report).subscribe((response: any) => {
        console.log(response);
        var blob = new Blob([s2ab(atob(data))], {type: ''}); <----------
        FileSaver.saveAs(blob, 'filename' + '.xlsx;); 
        });
    
       private s2ab(s) {
         var buf = new ArrayBuffer(s.length);
         var view = new Uint8Array(buf);
         for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
         return buf;
        }*
    

    如果成功,别忘了给这个答案发学分 blob from xlsx

    【讨论】:

    • 谢谢,当我尝试这个时,我有一个 200 错误:SyntaxError: Unexpected token P in JSON。前端也有什么可做的吗?
    • 使用 create 方法检查您在服务后端发送的 json。检查console.log(报告)。您在后端发送的 JSON 中的某些内容是错误的。同时删除观察:响应。正如我认为的那样,我可以看到这种观察可能导致错误
    • 这很奇怪,在这段代码之前我没有任何错误。我删除了观察:响应,但它没有改变任何东西:/。当我评论 writeOutputStream 时,错误消失了,但这不是解决方案^^
    • 我添加了这个 => let HTTPOptions:Object = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }), responseType: 'blob' } 现在它下载但是文件为空。
    • 我比较了客户端和本地文档的大小,结果不一样。对于客户端,它是一个空页面(9 字节),但本地报告已满,而且他的大小更大(5,09 KB)。你有什么想法吗?
    猜你喜欢
    • 2016-02-08
    • 1970-01-01
    • 2020-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-02
    • 2019-12-03
    相关资源
    最近更新 更多