Poi Excel 動態(tài)變化行高,動態(tài)創(chuàng)建Sheet
需求
- Excel 最終需要由A4紙打印出來
- 標題名稱需要動態(tài)變化
- 行高自動變化
- 每頁都需要保留標題
分析
基礎需求即填充標題填充數(shù)據(jù),設置樣式,基礎需求可以通過easyExcel或者Poi的API來實現(xiàn),但是由于需求3、4,easyExcel并不支持,只能選擇使用Apache Poi。
Apache POI沒有直接的API來自動調(diào)整行高,所以行高需要手動計算
每頁都需要保留標題,這個需求導致不能使用excel軟件默認的分頁,所以要求控制每頁的數(shù)據(jù)總量填充后整體高度需要小于一張A4紙的高度,否則數(shù)據(jù)將被分頁。
那么大量的數(shù)據(jù)手動分頁,可以通過多sheet來實現(xiàn),確保每個sheet只存一張A4紙能放下的數(shù)據(jù),超過了則復制一個sheet然后繼續(xù)填充。
代碼
? 以下是一個實現(xiàn)的示例,根據(jù)自己的需求進行參考變動即可
-
獲取要填充的數(shù)據(jù)
List<ExcelEthicRecordData> records = this.getExcelEthicRecord(ethIds); -
獲取模板文件創(chuàng)建workbook對象
// 加載模板文件 獲取模板文件流 ClassPathResource templateResource = new ClassPathResource("excel-template/template.xlsx"); InputStream templateStream = templateResource.getInputStream(); Workbook workbook = WorkbookFactory.create(templateStream); -
設置標題樣式以及拷貝樣式(如果需要的話)
/** * 設置標題以及將樣式拷貝出來 * @param records 記錄 用于計算標題類型 * @param workbook workbook * @return 樣式 */ private static CellStyle setStyle(List<ExcelEthicRecordData> records, Workbook workbook) { // 計算總Sheet高度 后面需要保持總高不變 Sheet templateSheet = workbook.getSheetAt(0); // 獲取標題單元格 Row titleRow = templateSheet.getRow(1); // 第二行的索引為1 Cell titleCell = titleRow.getCell(0); // 假設標題在第一列 // 替換標題的“【類型】”為type變量 String title = titleCell.getStringCellValue(); title = title.replace("類型", calculateType(records)); titleCell.setCellValue(title); // 從模板文件的標題列中獲取樣式,主要是邊框 CellStyle borderStyle = templateSheet.getRow(3).getCell(0).getCellStyle(); // 創(chuàng)建新的字體樣式 Font font = workbook.createFont(); font.setFontHeightInPoints((short) 9); // 縮小字號為9號字 borderStyle.setFont(font); borderStyle.setWrapText(true); // 自動換行 return borderStyle; } -
動態(tài)變化行高和創(chuàng)建Sheet并且填充數(shù)據(jù)
CellStyle borderStyle = setStyle(records, workbook); int currentSheetIndex = 0; int currentRowNumber = 4; // 從第五行開始填充數(shù)據(jù) short defaultHeight = 40 * 20; // 默認行高為40 可根據(jù)自己需要進行設置 // 獲取當前Sheet Sheet currentSheet = workbook.getSheetAt(currentSheetIndex); // 在POI庫中,Excel的行高是以1/20個點為單位進行設定的, A4 紙包含邊距 1150個點數(shù),模板文件默認行高設置大約40個點數(shù) // 根據(jù)打印結果計算,行高40的情況下大概能打印12行 根據(jù)自己需要計算 int maxRowsPerPage = defaultHeight * 12; int totalHeight = 0; // 記錄當前頁已使用的高度 for (ExcelEthicRecordData record : records) { // 計算行高,這里假設每14個字符占一行 int recordHeight = Math.max(record.getNum().length(), record.getSchemeName().length()) / 14 + 1; // 根據(jù)實際內(nèi)容長度調(diào)整行高 short height = (recordHeight > 1) ? (short) (256 * recordHeight) : defaultHeight; // 如果這條記錄的高度使得當前Sheet的高度超過了最大高度,那么就創(chuàng)建一個新的Sheet if (totalHeight + height > maxRowsPerPage) { // 如果添加新的行會超過總高度 // 創(chuàng)建新的Sheet,并將模板Sheet的格式復制到新的Sheet String sheetName = "Sheet" + ++currentSheetIndex; cloneSheetStyle(workbook, sheetName); // 重置當前高度和行數(shù) totalHeight = 0; currentRowNumber = 4; // 如果你的標題占用了4行,那么數(shù)據(jù)從第5行開始 currentSheet = workbook.getSheetAt(currentSheetIndex); } // 在當前Sheet的指定行創(chuàng)建新的行 Row newRow = currentSheet.createRow(currentRowNumber); newRow.setHeight(height); // 應用樣式到新的單元格上 填充數(shù)據(jù) for (int i = 0; i < 8; i++) { Cell cell = newRow.createCell(i); cell.setCellStyle(borderStyle); if (i == 0) { cell.setCellValue(record.getNum()); } else if (i == 1) { cell.setCellValue(record.getSchemeName()); } } // 更新當前高度和行數(shù) totalHeight += height; currentRowNumber++; } -
克隆樣式代碼
private void cloneSheetStyle(Workbook workbook, String sheetName) { // 獲取模板sheet Sheet templateSheet = workbook.getSheetAt(0); // 復制模板sheet到目標sheet Sheet newSheet = workbook.cloneSheet(workbook.getSheetIndex(templateSheet)); // 保留前四行,移除其他所有行 for (int i = newSheet.getLastRowNum(); i >= 4; i--) { Row row = newSheet.getRow(i); if (row != null) { newSheet.removeRow(row); } } // 重命名新建的sheet workbook.setSheetName(workbook.getSheetIndex(newSheet), sheetName); } -
相應代碼
private static ResponseEntity<byte[]> getResponseEntity(Workbook workbook) throws IOException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); workbook.write(outputStream); // 構建下載響應 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setContentDispositionFormData("attachment", "xxxx.xlsx"); byte[] fileBytes = outputStream.toByteArray(); return ResponseEntity.ok() .headers(headers) .contentLength(fileBytes.length) .body(fileBytes); }

浙公網(wǎng)安備 33010602011771號