HSSFWorkbook導出excel時會有65535行的限制,當我們數據量大的時候可以分多個sheet頁的方案來解決,
但是每個sheet頁都需要讀取下載模版文件的表頭,而poi庫對一個excel之間的多sheet頁都讀取模版excel文件不支持,
本文的思路是先生成多個excel文件到內存,然后再將這些excel復制到一個文件的多個sheet頁中。
一 . 首先查出來數據總數,按6萬條一個excel進行生成。
//生成excel @GetMapping("/generate") public void generate(String fileName){ List<Map<String,Object>> dataList=new ArrayList(); //測試數據 for (int i=0;i<200000;i++){ Map m1 = new HashMap(); m1.put("Zara", "8bbb"); m1.put("Mahnaz", "31cc"); m1.put("Ayan", "12"); m1.put("Daisy", "14111aa"); dataList.add(m1); } //單個sheet處理65536條最多 final int sheetNum= new Double(Math.ceil((float)dataList.size()/60000)).intValue();
HSSFWorkbook sumWorkBook =new HSSFWorkbook(); for (int i=0;i<sheetNum;i++){ HSSFWorkbook workbook1=exportExcelByPostFix(dataList.subList(60000*i, (i!=(sheetNum-1)?(60000*(i+1)):dataList.size()))); HSSFSheet sheet1=workbook1.getSheetAt(0); HSSFSheet newsheet =sumWorkBook.createSheet("sheet"+(i+1)); ExcelUtil.copySheet(sumWorkBook,sheet1,newsheet); } //生成文件 exportFile(sumWorkBook,fileName); return Result.succ("copy"); }
二 . 將每6萬條數據生成一個excel到內存中,即excel的第一個sheet頁
public HSSFWorkbook exportExcelByPostFix(List<Map<String,Object>> dataList){ //獲取模版表頭 Resource resourceData=new DefaultResourceLoader().getResource("classpath:doctemp/temp.xls"); InputStream inputStream=null; HSSFWorkbook wb=null; try { //獲取輸入流 inputStream= resourceData.getInputStream(); //創建帶表頭的工作表 wb=new HSSFWorkbook(inputStream); //設置單元格基礎樣式,加邊框,加基礎黑框 CellStyle hssfCellStyle=wb.createCellStyle(); hssfCellStyle.setBorderBottom(BorderStyle.THIN); hssfCellStyle.setBorderLeft(BorderStyle.THIN); hssfCellStyle.setBorderRight(BorderStyle.THIN); hssfCellStyle.setBorderTop(BorderStyle.THIN); //字居中 hssfCellStyle.setAlignment(HorizontalAlignment.CENTER); //獲取第一個sheet頁 HSSFSheet sheet=wb.getSheetAt(0); //前五行表頭 int count=5; ExcelUtil.exportForData(dataList,sheet,hssfCellStyle,count); } catch (IOException e){ } finally { } return wb; }
三.生成excel工具類,以及復制sheet頁的方法
public class ExcelUtil { /** * sheet復制 */ public static void copySheet(HSSFWorkbook wb, HSSFSheet fromSheet, HSSFSheet toSheet){ //合並區域處理 mergeSheetAllRegion(fromSheet, toSheet); // 列寬 int length = fromSheet.getRow(fromSheet.getFirstRowNum()).getLastCellNum(); for (int i = 0; i <= length; i++) { toSheet.setColumnWidth(i, fromSheet.getColumnWidth(i)); } int flag=0; //設置單元格基礎樣式,加邊框,加基礎黑框 CellStyle hssfCellStyle=wb.createCellStyle(); hssfCellStyle.setBorderBottom(BorderStyle.THIN); hssfCellStyle.setBorderLeft(BorderStyle.THIN); hssfCellStyle.setBorderRight(BorderStyle.THIN); hssfCellStyle.setBorderTop(BorderStyle.THIN); //字居中 hssfCellStyle.setAlignment(HorizontalAlignment.CENTER); for (Iterator rowIt = fromSheet.rowIterator(); rowIt.hasNext(); ) { HSSFRow oldRow = (HSSFRow) rowIt.next(); HSSFRow newRow = toSheet.createRow(oldRow.getRowNum()); flag++; copyRow(wb, oldRow, newRow,flag,hssfCellStyle); } } /** * 行復制 */ private static void copyRow(HSSFWorkbook wb, HSSFRow oldRow, HSSFRow toRow,int flag, CellStyle hssfCellStyle) { toRow.setHeight(oldRow.getHeight()); for (Iterator cellIt = oldRow.cellIterator(); cellIt.hasNext(); ) { HSSFCell tmpCell = (HSSFCell) cellIt.next(); HSSFCell newCell = toRow.createCell(tmpCell.getColumnIndex()); copyCell(wb, tmpCell, newCell,flag,hssfCellStyle); } } /** * 合並單元格處理 */ private static void mergeSheetAllRegion(HSSFSheet fromSheet, HSSFSheet toSheet) { int sheetMergeCount = fromSheet.getNumMergedRegions(); CellRangeAddress cellR = null; for (int i = 0; i < sheetMergeCount; i++) { cellR = fromSheet.getMergedRegion(i); toSheet.addMergedRegion(cellR); } } /** * 復制單元格 */ private static void copyCell(HSSFWorkbook wb, HSSFCell fromCell, HSSFCell toCell, int flag, CellStyle hssfCellStyle) { //excel表頭有5行 if(flag<6){ HSSFCellStyle newstyle = wb.createCellStyle(); // 復制單元格樣式 newstyle.cloneStyleFrom(fromCell.getCellStyle()); // 樣式 toCell.setCellStyle(newstyle); } else { //其它的單元格用標准格式 //單元格格式過多會拋出異常,不支持創建太多 toCell.setCellStyle(hssfCellStyle); } if (fromCell.getCellComment() != null) { toCell.setCellComment(fromCell.getCellComment()); } // 不同數據類型處理 CellType fromCellType = fromCell.getCellType(); toCell.setCellType(fromCellType); if (fromCellType == CellType.NUMERIC) { if (DateUtil.isCellDateFormatted(fromCell)) { toCell.setCellValue(fromCell.getDateCellValue()); } else { toCell.setCellValue(fromCell.getNumericCellValue()); } } else if (fromCellType == CellType.STRING) { toCell.setCellValue(fromCell.getRichStringCellValue()); } else if (fromCellType == CellType.BLANK) { // nothing21 } else if (fromCellType == CellType.BOOLEAN) { toCell.setCellValue(fromCell.getBooleanCellValue()); } else if (fromCellType == CellType.ERROR) { toCell.setCellErrorValue(fromCell.getErrorCellValue()); } else if (fromCellType == CellType.FORMULA) { toCell.setCellFormula(fromCell.getCellFormula()); } else { // nothing29 } } /** * 創建單元格 */ public static void createCell(Row rows,int column,String value,CellStyle hssfCellStyle){ Cell cell=rows.createCell(column); cell.setCellValue(value); cell.setCellStyle(hssfCellStyle); } /** * 根據數據組裝cell數據 * count=5表示從第6行開始生成單元格,前面5行是表頭 */ public static void exportForData(List<Map<String,Object>> list, HSSFSheet hssfSheet, CellStyle hssfCellStyle,int count){ if(list!=null&& list.size()!=0){ for (int i=0;i<list.size();i++){ //創建行 Row rows=hssfSheet.createRow(count); Map<String,Object> map= list.get(i); //是否總計數據 int j=0; Set<String> sets= map.keySet(); if(sets==null||sets.size()<1){ continue; } for (String key:sets){ createCell(rows,j,String.valueOf(map.get(key)),hssfCellStyle); //在for循環中。單元格緯度下調用該函數,會極大降低效率 //所以在最后一行數據時,才調用這個函數 if(i==list.size()-1){ hssfSheet.autoSizeColumn(j);//按內容撐開單元格寬度 } j++; } count++; } } } }
四,將生成的每個excel的sheet1合並到一個總的excel中,代碼在第一步已經列出。然后生成文文件
private void exportFile(HSSFWorkbook workbook,String fileName){ String c="/workspace/java/"; File file=new File(c); if(!file.exists()){ file.mkdir(); } String exportFilePath=file +"/"+fileName+".xls"; FileOutputStream outputStream=null; try { outputStream =new FileOutputStream(exportFilePath); workbook.write(outputStream); outputStream.flush(); } catch (Exception e){ } finally { } }
五,結束。需要注意的是window開發環境和部署的linux環境的差別