使用Angular和Spring Boot的Excel下载产生损坏的xls文件

时间:2018-08-16 11:42:23

标签: excel angular spring-boot download filesaver.js

我正在尝试为Spring引导应用程序编写xls下载。为了使用POI生成文件Iam。如果我直接从控制器下载文件而不将其传递到前端,则如下所示:

    //Wrote this one just for testing if the file is already corrupt here. 
    FileOutputStream fos = new FileOutputStream("C:\\dev\\directDownload.xls");
    fos.write(byteArray);
    fos.flush();
    fos.close();
}

工作正常,文件看起来像这样:

从后端下载

xls而不将其传递给angular:

enter image description here

但这不是我的目标。我打算将Outputstream传递给我的角度组件。组件从服务类调用函数。此类从控制器获取响应,并将其传递回我的组件。在用户界面中,下载对话框打开。问题是下载的文件看起来像这样(通过excel或Open Office打开文件无关紧要):

当前xls:

enter image description here

我的Java控制器:

   @CrossOrigin(exposedHeaders = "Content-Disposition")
@RequestMapping(value = "/report/file", produces = "application/vnd.ms-excel;charset=UTF-8")
public void getReportFile(@RequestParam(name = "projectNumber") final String projectNumber,
                          @RequestParam(name = "month") final int month, @RequestParam(name = "year") final int year,
                          @RequestParam(name = "employee") final int employee,
                          @RequestParam(name = "tsKey") final String tsKey,
                          final HttpServletResponse response) throws IOException {


    response.setContentType("application/vnd.ms-excel;charset=UTF-8");
    String excelFileName = "test.xls";
    String headerKey = "Content-Disposition";
    String headerValue = String.format("attachment; filename=\"%s\"",
            excelFileName);
    response.setHeader(headerKey, headerValue);

    //Here I create the workbook that I want to download
    ProjectMonthReport report = reportService.getReport(projectNumber, month, year);
    //ExcelService builts the workbook using POI
    Workbook workbook = excelService.exportExcel(report, employee, tsKey);


    //The response is stored in an outputstream
    OutputStream out = response.getOutputStream();
    response.setContentType("application/vnd.ms-excel");
    byte[] byteArray = ((HSSFWorkbook)workbook).getBytes();
    out.write(byteArray);
    out.flush();
    out.close();


    //Wrote this one just for testing if the file is already corrupt here. --> It's fine.
    FileOutputStream fos = new FileOutputStream("C:\\dev\\directDownload.xls");
    fos.write(byteArray);
    fos.flush();
    fos.close();
}

使用POI构建文件的Java Service方法:

     public Workbook exportExcel(final ProjectMonthReport report, final int employee, final String tsKey) throws IOException,
        InvalidFormatException {
    Workbook workbook = new HSSFWorkbook();

    CreationHelper createHelper = workbook.getCreationHelper();

    // Create a Sheet
    Sheet sheet = workbook.createSheet("Employee");

    // Create a Font for styling header cells
    Font headerFont = workbook.createFont();
    headerFont.setBold(true);
    headerFont.setFontHeightInPoints((short) 14);
    headerFont.setColor(IndexedColors.RED.getIndex());

    // Create a CellStyle with the font
    CellStyle headerCellStyle = workbook.createCellStyle();
    headerCellStyle.setFont(headerFont);

    Row headeRow = sheet.createRow(0);
    Cell dateHeader = headeRow.createCell(0);
    dateHeader.setCellValue("Datum");
    Cell startHeader = headeRow.createCell(1);
    startHeader.setCellValue("Beginn");
    Cell endHeader = headeRow.createCell(2);
    endHeader.setCellValue("Ende");
    Cell activityHeader = headeRow.createCell(3);
    activityHeader.setCellValue("Tätigkeitsbereit");
    Cell cardHeader = headeRow.createCell(4);
    cardHeader.setCellValue("Kartennummer");

    List<WorkDescriptionDetail> details = report.getEmployees().get(employee).getKeyDetailMap().get(Integer.valueOf(tsKey)).getDetailList();

    int counter = 1;
    for (WorkDescriptionDetail detail : details) {

        List <String> stringList= detail.toStringList();

        Row row = sheet.createRow(counter);
        Cell cellDate = row.createCell(0);
        cellDate.setCellValue(stringList.get(0));

        Cell cellStart = row.createCell(1);
        cellStart.setCellValue(stringList.get(1));

        Cell cellEnd = row.createCell(2);
        cellEnd.setCellValue(stringList.get(2));

        Cell cellActivity = row.createCell(3);
        cellActivity.setCellValue(stringList.get(3));
        counter ++;
    }

    return workbook;
}

我的角度分量:

  saveFile(employee: string, tsKey:string) {
   this.subscription = this.reportService.saveXlsFile(this.projectNumber, this.year, this.month, employee, tsKey)
        .subscribe(response=> {
            console.log(response);
                let mediatype = 'application/vnd.ms-excel;charset=UTF-8';

                const data  = new Blob(["\ufeff",response.arrayBuffer()], {type: mediatype});
                console.log(data);
                saveAs(data, 'test.xls');

            },
            error => console.log("error downloading the file"));

}

Ts服务功能,称为:

    saveXlsFile(projectNumber:string, year:string, month:string, empId: string, tsKey:string) {
    let params:URLSearchParams = new URLSearchParams();
    params.set('projectNumber', projectNumber);
    console.log(projectNumber);
    params.set('month', month);
    console.log(month);
    params.set( 'year', year);
    console.log(year);
    params.set('employee', empId);
    console.log(empId);
    params.set('tsKey', tsKey);
    console.log(tsKey);

    return this.http.get(this.baseUrl + "/file", { search: params } );
}

我试图通过Postman检索响应并直接下载文件。当我这样做时,Excel无法打开该文件(Excel刚刚崩溃了),但是我可以在OpenOffice版本中打开该文件,并且工作正常。它也没有损坏。

最近几天我一直在网上搜索,我认为这可能是前端引起的一个紧迫问题。但是也许这也是SpringBoot在这里扮演我的角色。有什么建议吗?

谢谢您的帮助!

1 个答案:

答案 0 :(得分:0)

嘿,昨天我自己找到了解决此问题的方法。在角度服务中添加以下内容:

   return this.http.get(this.baseUrl + "/file", { search: params, responseType: ResponseContentType.Blob }).map(
        (res) => {
            return new Blob([res.blob()], { type: 'application/vnd.ms-excel' });
        });

之后,您需要像这样修改组件:

   saveFile(employee: string, tsKey:string) {
   this.subscription = this.reportService.saveXlsFile(this.projectNumber, this.year, this.month, employee, tsKey)
        .subscribe(response=> {
            console.log(response);
                let mediatype = 'application/vnd.ms-excel';
                saveAs(response, 'test.xlsx');
            },
            error => console.log("error downloading the file"));
}

所以问题在于我没有在响应中得到blob对象。...