Я пытаюсь записать данные в шаблон Excel, который содержит много формул и стилей. Если я скопировал формулу / форматирование в 100 строк * 601 ячеек, Excel загрузится через секунду после записи данных, но как только я увеличу его до 3000 строк * 601 ячеек, и даже если я запишу его в 70 строк, это займет вечность и зависает сервер. Это происходит потому, что workbook.write (outputtream) занимает слишком много времени.
Если я увеличу размер кучи, он будет работать с 1500 строками, загрузка которого занимает от 15 до 20 секунд.
Я пробовал SXSSFWorkbook, но это не позволяет мне писать в существующих строках. Чтобы избежать этого, я держу одну XSSFWorkbook для чтения данных и SXSSFWorkbook для записи, проблема в том, что я не смог получить цвета и стиль из моего фактического шаблона в другой, и данные также испортились.
Это работает, но я должен увеличить размер кучи с увеличением количества строк, я проверил его на 1500 строк, результирующий размер файла составляет 3,5 МБ.
private Workbook dumpDataToMaster(List<Map<String, Object>> excelData,Map<String, String> fileType) throws IOException {
Workbook workbook = new XSSFWorkbook(this.getClass().getResourceAsStream("/excel_templates/"+fileType.get("file")));
Sheet sheet = workbook.getSheet(fileType.get("sheetName"));
Iterator<Cell> headerItr = sheet.getRow(3).iterator();
List<String> headers = new ArrayList<>();
while(headerItr.hasNext()) {
headers.add(headerItr.next().getStringCellValue());
}
int headersSize = headers.size();
int excelDataSize = excelData.size();
IntStream.range(0,excelDataSize).forEach(eIndex->{
Row dataRow = sheet.getRow(eIndex+4);
IntStream.range(0,headersSize).forEach(index->{
Object value = excelData.get(eIndex).get(headers.get(index));
if(value != null) {
if (value instanceof String) {
dataRow.getCell(index).setCellValue((String)value);
} else if(value instanceof Number) {
dataRow.getCell(index).setCellValue(((Number)value).doubleValue());
} else if(value instanceof Date) {
dataRow.getCell(index).setCellValue((Date)value);
}
}
});
});
sheet.getRow(1).getCell(1).setCellValue(Calendar.getInstance().getTime());
workbook.setForceFormulaRecalculation(true);
return workbook;
}
Контроллер для вышеуказанного метода выглядит так
public void downloadDDTemplate(@RequestParam String values, @OrgModelAttribute("sessionElements") SessionElements sessionElements, HttpServletResponse response) throws IOException {
OrderTemplateType orderTemplateType = objectMapper.readValue(values, OrderTemplateType.class);
response.setHeader(Constant.CONTENT_DISPOSITION,
"attachment; filename=\"" + orderTemplateType.getDisplay()+" - Template - "
+ DateTimeFormatConfiguration.getFileNameDateFormat().format(Calendar.getInstance().getTime())
+ ".xlsx\"");
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
orderMasterService.downloadDDTemplate(orderTemplateType).write(response.getOutputStream());
response.flushBuffer();
}
второй метод, который я попробовал, это
private Workbook dumpDataToMaster(List<Map<String, Object>> excelData,Map<String, String> fileType, HttpServletResponse response) throws IOException, InvalidFormatException {
Workbook workbook = new XSSFWorkbook(this.getClass().getResourceAsStream("/excel_templates/"+fileType.get("file")));
XSSFWorkbook readWb = new XSSFWorkbook(workbook);
Sheet readSheet = readWb.getSheet(fileType.get("sheetName"));
//inputStream.close();
SXSSFWorkbook writeWb = new SXSSFWorkbook();
writeWb.setCompressTempFiles(true);
SXSSFSheet writeSheet = writeWb.createSheet(fileType.get("sheetName"));//(SXSSFSheet) wb.getSheet(fileType.get("sheetName"));
writeSheet.setRandomAccessWindowSize(1600);
Iterator<Cell> headerItr = readSheet.getRow(3).iterator();
List<String> headers = new ArrayList<>();
CellStyle dateStyle = writeWb.createCellStyle();
CreationHelper createHelper = writeWb.getCreationHelper();
dateStyle.setDataFormat(
createHelper.createDataFormat().getFormat("dd-mm-yyyy"));
while(headerItr.hasNext()) {
String value = headerItr.next().getStringCellValue();
headers.add(value);
Row auxWriteRow = writeSheet.createRow(3);
Cell auxWriteCell = auxWriteRow.createCell(headers.size()-1);
auxWriteCell.setCellValue(value);
}
int headersSize = headers.size();
int excelDataSize = excelData.size();
IntStream.range(0,excelDataSize).forEach(eIndex->{
Row dataRow = readSheet.getRow(eIndex+4);
Row writeRow = writeSheet.createRow(eIndex+4);
IntStream.range(0,headersSize).forEach(index->{
Cell writeCell = writeRow.createCell(index);
Cell readCell = dataRow.getCell(index);
Object value = excelData.get(eIndex).get(headers.get(index));
if(readCell != null && CellType.FORMULA.equals(readCell.getCellType())) {
writeCell.setCellFormula(readCell.getCellFormula());
}
writeCell.getCellStyle();
if(value != null) {
if (value instanceof String) {
XSSFCellStyle newCellStyle = (XSSFCellStyle) writeCell.getSheet().getWorkbook().createCellStyle();
writeCell.setCellStyle(copyCellStyle((XSSFCell)readCell, newCellStyle));
writeCell.setCellType(readCell.getCellType());
writeCell.setCellValue((String)value);
} else if(value instanceof Number) {
XSSFCellStyle newCellStyle = (XSSFCellStyle) writeCell.getSheet().getWorkbook().createCellStyle();
writeCell.setCellStyle(copyCellStyle((XSSFCell)readCell, newCellStyle));
writeCell.setCellStyle(readCell.getCellStyle());
writeCell.setCellType(readCell.getCellType());
writeCell.setCellValue(((Number)value).doubleValue());
} else if(value instanceof Date) {
writeCell.setCellStyle(dateStyle);
writeCell.setCellType(readCell.getCellType());
writeCell.setCellValue((Date)value);
}
}
});
});
int lastRow = sheet.getLastRowNum();
for (int eIndex=0; eIndex<=lastRow; eIndex++) {
Row dataRow = sheet.getRow(eIndex+excelDataSize+4);
if(dataRow == null)
break;
sheet.removeRow(dataRow);
}
Cell cell = writeSheet.createRow(1).createCell(1);
cell.setCellStyle(dateStyle);
cell.setCellValue(Calendar.getInstance().getTime());
XSSFFormulaEvaluator.evaluateAllFormulaCells(workbook);
writeWb.setForceFormulaRecalculation(true);
writeWb.write(response.getOutputStream());
writeWb.close();
readWb.close();
return writeWb;
}
Есть ли способ добиться этого быстрее, с меньшим объемом памяти при потреблении.