编辑:
如果我直接从浏览器命中endpoint,文件就会被正确下载。所以我猜问题出在前面,以及用接收到的数据创建和保存文件的方式。
我有一个Java/spring boot的应用程序,我想在其中构建一个APIendpoint,它创建并返回一个可下载的excel文件。以下是我的控制器endpoint:
@GetMapping(path = "/informe/{informeDTO}")
public ResponseEntity<InputStreamResource> generarInforme(@PathVariable(value = "informeDTO") String informeDTOString) throws JsonParseException, JsonMappingException, IOException {
final InformeDTO informeDTO =
new ObjectMapper().readValue(informeDTOString, InformeDTO.class);
List<InformeDTO> listDatosinformeDTO = utilsService.getDatosInformeDTO(informeDTO);
for (InformeDTO informeDTO2 : listDatosinformeDTO) {
logger.debug(informeDTO2);
}
ByteArrayInputStream in = createReport(listDatosinformeDTO);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment; filename=IOPreport.xlsx");
return ResponseEntity.ok().headers(headers)
.contentType(
MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))
.body(new InputStreamResource(in));
}
这是角度控制器:
function generarInformeIOP(){
InformesService.generarInformeIOP($scope.informeView.sociedad, $scope.informeView.area, $scope.informeView.epigrafe,
$scope.informeView.cuenta, $scope.informeView.status, $scope.informeView.organizationalUnit,
$scope.informeView.societyGL, $scope.informeView.calculationType, $scope.informeView.provincia, $scope.informeView.financialSegment,
$scope.informeView.loadDateFrom, $scope.informeView.loadDateTo, $scope.informeView.incomeDateFrom, $scope.informeView.incomeDateTo)
.then(
function(response)
{
var blob = new Blob([response.data], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"
});
saveAs(blob, "IOPreport.xlsx");
$scope.informeFunctionality.errorMessage = '';
},
function(errResponse)
{
console.log("ERROR: " + errResponse.data);
$scope.informeFunctionality.errorMessage = "Ha ocurrido un error inesperado: " + errResponse.data.error +
": " + errResponse.data.message;
}
)
}
和服务:
....
$http.get(urls.SERVICE_API + "informe/"+ angular.toJson(informeDTO)).then(
function(response) {
console.log("GenerarInformeIOP - success");
deferred.resolve(response);
}, function(errResponse) {
console.log("GenerarInformeIOP - error");
deferred.reject(errResponse);
});
...
生成成功,文件已下载,但我认为它已损坏,因为Excel无法打开它。
有什么不对劲吗?
编辑(添加createReport):
private ByteArrayInputStream createReport(List<InformeDTO> datosInforme) {
ByteArrayInputStream result =null;
try (Workbook workbook = new XSSFWorkbook(); ByteArrayOutputStream out = new ByteArrayOutputStream();) {
Set<String> columns = new LinkedHashSet<String>();
// Coumnas fijas
columns.add("Cuenta");
columns.add("Epigrafe");
columns.add("Descripcion");
columns.add("Total_Importe");
// Columnas dinamicas
/*
* Tedremos que recorrer todas las filas puesto que no sabremos si una traera
* menos periodos que otra de esta manera obtendremos todos los periodos
*/
for (InformeDTO informeDTO : datosInforme) {
for (Map.Entry<String, Double> entry : informeDTO.getTotalByPeriodoContable().entrySet()) {
columns.add(entry.getKey());
}
}
/*
* CreationHelper helps us create instances for various things like DataFormat,
* Hyperlink, RichTextString etc in a format (HSSF, XSSF) independent way
*/
// CreationHelper createHelper = workbook.getCreationHelper();
// Create a Sheet
Sheet sheet = workbook.createSheet("IOPReport");
// 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);
// Create a Row
Row headerRow = sheet.createRow(0);
// Creating cells
int i = 0;
for (String value : columns) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(value);
cell.setCellStyle(headerCellStyle);
i++;
}
// Create Other rows and cells with employees data
int rowNum = 1;
int cellDynamicNum = 0;
for (InformeDTO informeDTO : datosInforme) {
Row row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(informeDTO.getCuenta());
row.createCell(1).setCellValue(informeDTO.getEpigrafe());
row.createCell(2).setCellValue(informeDTO.getDescripcion_epigrafe());
row.createCell(3).setCellValue("No Data");
cellDynamicNum = 4;
for (Map.Entry<String, Double> entry : informeDTO.getTotalByPeriodoContable().entrySet()) {
row.createCell(cellDynamicNum).setCellValue(entry.getValue());
cellDynamicNum++;
}
}
// Resize all columns to fit the content size
for (i = 0; i < columns.size(); i++) {
sheet.autoSizeColumn(i);
}
// Write the output to a file
workbook.write(out);
result = new ByteArrayInputStream(out.toByteArray());
out.close();
workbook.close();
} catch (Exception e) {
logger.debug("Excepcion en la creacion del report " + e);
}
return result;
}
问候
我不确定为什么使用responseEntity
。我有另一个使用字节数组responseEntity
的工作解决方案。下面附上了一些代码片段:
创建工作簿后,将其写入OutputStream:
private final MediaType mediaType = MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
...
...
// at the end
ByteArrayOutputStream stream = new ByteArrayOutputStream();
workbook.write(stream);
return getDownload(stream.toByteArray(), filename, mediaType);
....
下载方法:
public static ResponseEntity<byte[]> getDownload(byte[] content, String filename, MediaType mediaType) {
HttpHeaders headers = new HttpHeaders();
headers.setContentLength(content.length);
headers.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename);
headers.set(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);
headers.setContentType(mediaType);
return new ResponseEntity<>(content, headers, HttpStatus.OK);
}
如果能行就告诉我。
在此处生成输出时:
result = new ByteArrayInputStream(out.toByteArray());
工作簿在关闭之前不会保存到out
中。因此您需要将顺序更改为:
workbook.close()
result = new ByteArrayInputStream(out.toByteArray());
关闭ByteArrayOutputStream并不是必须的,但如果保留它也没关系。
我正在使用ApachePOI,我创建了一个XSSF工作簿,并尝试打开一个xlsx文件。它在当地的一个地方很有效。但是,当我用Excel打开真正服务器(AWS EC2、Tomcat8、JDK 1.8)上的Excel文件时,它显示文件已损坏(.xls工作)。这是我的代码: 本地Spring4, jdk1.8, tomcat 8.0, maven 真正的AWS EC2亚马逊linux2,jdk1。8、t
我正在使用Cordova构建一个Android应用程序,因为我对Android一无所知。 我执行了以下步骤来创建和运行Cordova应用程序: 安装JDK 8 安装Gradle 安装Android Studio 在Android Studio中使用SDK管理器安装SDK版本28(我的目标是Fire TV设备) (目标API级别28) 这是最后一个命令输出的结尾: 我尝试卸载并重新安装SDK,但我仍
我正在ServletOutputStream上编写一个excel文件(使用HSSFWorkBook for xls和XSSFWorkBook forxlsx)。作为ServletResponse的一部分下载的excel已损坏并包含垃圾字符。 我尝试过将Excel文件写入FileOutpuStream,它工作正常。Excel文件可读且完好无损。 已经检查了关于同一问题的其他几个StackOverfl
当我构建我的android应用程序时,它给出了错误“安装的构建工具版本30.0.3被损坏。删除并使用SDK管理器重新安装”我试图通过更新我的SDK管理器来修复这个问题,但它不起作用。我如何修复这个错误。
我正在使用java中的Apache poi库生成excel报表。 为了生成excel报表,我正在读取使用管道分隔的文本文件,并将其写入excel表单中。 有人对此有什么建议吗。读写时是否有内存问题。文件是逐行读取,逐页写入。
Docx4J生成的Excel工作簿总是说损坏了,但我无法确定Excel不喜欢底层XML的什么,更不用说如何修复它了。 我的用例如下:我试图定期自动生成一个带有图表和图形的excel工作簿。只有原始数据会改变,但随着原始数据的改变,其他一切都会动态更新。 null null 在我的空白工作簿之前和之后 欢迎所有的想法。