Excel 使用 Angular 下载和 Spring 引导生成损坏的 xls 文件
Excel download using Angular and Spring Boot produces corrupt xls file
我正在尝试为我的 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:
然而那不是我的目标。我打算将 Outputstream 传递到我的 angular 组件。组件从服务 class 调用函数。此 class 从控制器获取响应并将其传递回我的组件。在 UI 中打开下载对话框。问题是,下载的文件看起来像这样(不管是通过 excel 还是 open office 打开):
损坏的 xls:
我的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服务方式:
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;
}
我的angular组件:
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 也在玩我。有什么建议吗?
感谢您的帮助!
嘿,我昨天自己找到了解决这个问题的办法。在 angular 服务中添加以下内容:
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 对象....
我正在尝试为我的 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:
然而那不是我的目标。我打算将 Outputstream 传递到我的 angular 组件。组件从服务 class 调用函数。此 class 从控制器获取响应并将其传递回我的组件。在 UI 中打开下载对话框。问题是,下载的文件看起来像这样(不管是通过 excel 还是 open office 打开):
损坏的 xls:
我的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服务方式:
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;
}
我的angular组件:
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 也在玩我。有什么建议吗?
感谢您的帮助!
嘿,我昨天自己找到了解决这个问题的办法。在 angular 服务中添加以下内容:
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 对象....