Apache POI是一個純Java編寫用來操作Microsoft Office的框架,最常見的應用是讓服務器后台按照特定的數據生成Excel表格提供給用戶實用。前段時間因為項目的需要被大量使用,使用以后的感覺是——低效而繁瑣。也在網上找了不少別人的心得,但是感覺都寫的過於復雜,因此結合客戶的實際需求自己封裝了幾個實用的方法提供給真正有這方面需要的朋友參考。
首先,就Excel來說分為2007和2003兩個版本,對應的后綴名為.xlsx和.xls。對此poi也提供了兩套Workbook實現,分別為XSSFWorkbook和HSSFWorkbook。但是接口都是統一的,因此在使用的時候完全可以只針對接口編程。
其次,使用poi讀取表格中的數據比較方便但是從數據庫中讀取數據再利用poi來生成就比較復雜。因此我推薦的做法是先利用Office設計好表格並保存成模板,再往模板里插入數據生成文件。
最后,工具類提供的靜態方法均以Workbook為返回值,通常為了完成一次表格生成必須多次調用。如果是提供給客戶下載只需要將response中的輸出流交給Workbook即可,具體方法不再這里贅述。
/** * Util提供的所有靜態方法返回的對象都是Workbook,最后一步根據需求再做處理 * @author learnhow * */ public class ExcelUtil { public static final int Excel2003 = 0; public static final int Excel2007 = 1; /** * 根據版本號,獲取Excel poi對象 * * @param edition * @param in * @return * @throws IOException */ public static Workbook getWorkbook(int edition, InputStream in) throws IOException { if (edition == 0) { return new HSSFWorkbook(in); } else if (edition == 1) { return new XSSFWorkbook(in); } return null; } /** * 從指定excel表格中逐行讀取數據 * * @param workbook * @param startRow * @param startCol * @param indexSheet * @return */ public static List<List<String>> getExcelString(Workbook workbook, int startRow, int startCol, int indexSheet) { List<List<String>> stringTable = new ArrayList<List<String>>(); // 獲取指定表對象 Sheet sheet = workbook.getSheetAt(indexSheet); // 獲取最大行數 int rowNum = sheet.getLastRowNum(); for (int i = startRow; i <= rowNum; i++) { List<String> oneRow = new ArrayList<String>(); Row row = sheet.getRow(i); // 根據當前指針所在行數計算最大列數 int colNum = row.getLastCellNum(); for (int j = startCol; j <= colNum; j++) { // 確定當前單元格 Cell cell = row.getCell(j); String cellValue = null; if (cell != null) { // 驗證每一個單元格的類型 switch (cell.getCellType()) { case Cell.CELL_TYPE_NUMERIC: // 表格中返回的數字類型是科學計數法因此不能直接轉換成字符串格式 cellValue = new BigDecimal(cell.getNumericCellValue()).toPlainString(); break; case Cell.CELL_TYPE_STRING: cellValue = cell.getStringCellValue(); break; case Cell.CELL_TYPE_FORMULA: cellValue = new BigDecimal(cell.getNumericCellValue()).toPlainString(); break; case Cell.CELL_TYPE_BLANK: cellValue = ""; break; case Cell.CELL_TYPE_BOOLEAN: cellValue = Boolean.toString(cell.getBooleanCellValue()); break; case Cell.CELL_TYPE_ERROR: cellValue = "ERROR"; break; default: cellValue = "UNDEFINE"; } } else { cellValue = ""; } // 生成一行數據 oneRow.add(cellValue); } stringTable.add(oneRow); } return stringTable; } /** * 根據給定的數據直接生成workbook * * @param workbook * @param sheetName * @param data * @return */ public static Workbook createExcel(Workbook workbook, String sheetName, List<List<String>> data) { Sheet sheet = workbook.createSheet(sheetName); for (int i = 0; i < data.size(); i++) { List<String> oneRow = data.get(i); Row row = sheet.createRow(i); for (int j = 0; j < oneRow.size(); j++) { Cell cell = row.createCell(j); cell.setCellValue(oneRow.get(j)); } } return workbook; } /** * 往指定的sheet表中插入數據,插入的方法是提供一組valueMap。int[]是2維數組代表需要插入的數據坐標,從0開始 * * @param workbook * @param sheetIndex * @param valueMap * @return */ public static Workbook insertExcel(Workbook workbook, int sheetIndex, Map<int[], String> valueMap) { Sheet sheet = workbook.getSheetAt(sheetIndex); Iterator<Entry<int[], String>> it = valueMap.entrySet().iterator(); while (it.hasNext()) { Entry<int[], String> cellEntry = it.next(); int x = cellEntry.getKey()[0]; int y = cellEntry.getKey()[1]; String value = cellEntry.getValue(); Row row = sheet.getRow(y); Cell cell = row.getCell(x); cell.setCellValue(value); } return workbook; } /** * 設置指定行的行高 * * @param workbook * @param rowHeight * @param sheetIndex * @param rowIndex * @return */ public static Workbook setRowHeight(Workbook workbook, int rowHight, int sheetIndex, int rowIndex) { Sheet sheet = workbook.getSheetAt(sheetIndex); Row row = sheet.getRow(rowIndex); row.setHeight((short) rowHight); return workbook; } /** * 設置列寬 * * @param workbook * @param columnWidth * @param sheetIndex * @param columnIndex * @return */ public static Workbook setColumnWidth(Workbook workbook, int columnWidth, int sheetIndex, int columnIndex) { Sheet sheet = workbook.getSheetAt(sheetIndex); sheet.setColumnWidth(columnIndex, columnWidth); return workbook; } /** * 刪除指定行 * * @param workbook * @param sheetIndex * @param rowIndex * @return */ public static Workbook removeRow(Workbook workbook, int sheetIndex, int rowIndex) { Sheet sheet = workbook.getSheetAt(sheetIndex); int lastRowNum = sheet.getLastRowNum(); if (rowIndex >= 0 && rowIndex < lastRowNum) { sheet.shiftRows(rowIndex + 1, lastRowNum, -1); } if (rowIndex == lastRowNum) { sheet.removeRow(sheet.getRow(rowIndex)); } return workbook; } /** * 在指定位置插入空白行 * * @param workbook * @param sheetIndex * @param rowIndex * @return */ public static Workbook insertBlankRow(Workbook workbook, int sheetIndex, int rowIndex) { Sheet sheet = workbook.getSheetAt(sheetIndex); int lastRowNum = sheet.getLastRowNum(); if (rowIndex >= 0 && rowIndex <= lastRowNum) { sheet.shiftRows(rowIndex, lastRowNum, 1); // 獲得上一行的Row對象 Row preRow = sheet.getRow(rowIndex - 1); short rowNum = preRow.getLastCellNum(); Row curRow = sheet.createRow(rowIndex); // 新生成的Row創建與上一個行相同風格的Cell for (short i = preRow.getFirstCellNum(); i < rowNum; i++) { Cell cell = preRow.getCell(i); CellStyle style = cell.getCellStyle(); curRow.createCell(i).setCellStyle(style); } return workbook; } return null; } /** * 根據sheet(0)作為模板重建workbook * * @param workbook * @param sheetNum * @param sheetNames * @return */ public static Workbook rebuildWorkbook(Workbook workbook, int sheetNum, String... sheetNames) { if(sheetNames.length == sheetNum){ for (int i = 0; i < sheetNum; i++) { workbook.cloneSheet(0); // 生成后面的工作表並指定表名 workbook.setSheetName(i + 1, sheetNames[i]); } // 刪除第一張工作表 workbook.removeSheetAt(0); return workbook; } return null; } }
