1. 程式人生 > >使用POI做的一個生成Excel的工具類。包含了匯出Excel和解析Excel方法

使用POI做的一個生成Excel的工具類。包含了匯出Excel和解析Excel方法


PoiExcelUtils.java


/**
 * 
 */
package com.common.office;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import net.sf.json.JSONArray;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.util.CellRangeAddress;

import com.common.reflect.ReflectUtils;

/**
 * Excel工具類
 * @author luolin
 */
public class PoiExcelUtils {
    private static NumberFormat format              = NumberFormat.getInstance();

    /** 日誌 */
    private static final Logger LOGGER              = Logger.getLogger(PoiExcelUtils.class);
    /** 列預設寬度 */
    private static final int    DEFAUL_COLUMN_WIDTH = 4000;

    /**
     * 1.建立 workbook
     * 
     * @return {@link HSSFWorkbook}
     */
    private HSSFWorkbook getHSSFWorkbook() {
        LOGGER.info("【建立 workbook】");
        return new HSSFWorkbook();
    }

    /**
     * 2.建立 sheet
     * 
     * @param hssfWorkbook {@link HSSFWorkbook}
     * @param sheetName sheet 名稱
     * @return {@link HSSFSheet}
     */
    private HSSFSheet getHSSFSheet(HSSFWorkbook hssfWorkbook, String sheetName) {
        LOGGER.info("【建立 sheet】sheetName : " + sheetName);
        return hssfWorkbook.createSheet(sheetName);
    }

    /**
     * 3.寫入表頭資訊
     * 
     * @param hssfWorkbook {@link HSSFWorkbook}
     * @param hssfSheet {@link HSSFSheet}
     * @param headers 列標題,陣列形式,
     *   			   如{"列標題
[email protected]
@columnWidth","列標題[email protected]@columnWidth","列標題[email protected]@columnWidth"} * 其中引數@columnWidth可選,columnWidth為整型數值 * @param title 標題 */ private void writeHeader(HSSFWorkbook hssfWorkbook, HSSFSheet hssfSheet, String[] headers, String title) { LOGGER.info("【寫入表頭資訊】"); // 頭資訊處理 String[] newHeaders = headersHandler(headers); // 初始化標題和表頭單元格樣式 HSSFCellStyle titleCellStyle = createTitleCellStyle(hssfWorkbook); // 標題欄 HSSFRow titleRow = hssfSheet.createRow(0); titleRow.setHeight((short) 500); HSSFCell titleCell = titleRow.createCell(0); // 設定標題文字 titleCell.setCellValue(new HSSFRichTextString(title)); // 設定單元格樣式 titleCell.setCellStyle(titleCellStyle); // 處理單元格合併,四個引數分別是:起始行,終止行,起始行,終止列 hssfSheet.addMergedRegion(new CellRangeAddress(0, 0, (short) 0, (short) (newHeaders.length - 1))); // 設定合併後的單元格的樣式 titleRow.createCell(newHeaders.length - 1).setCellStyle(titleCellStyle); // 表頭 HSSFRow headRow = hssfSheet.createRow(1); headRow.setHeight((short) 500); HSSFCell headCell = null; String[] headInfo = null; // 處理excel表頭 for (int i = 0, len = newHeaders.length; i < len; i++) { headInfo = newHeaders[i].split("@"); headCell = headRow.createCell(i); headCell.setCellValue(headInfo[0]); headCell.setCellStyle(titleCellStyle); // 設定列寬度 setColumnWidth(i, headInfo, hssfSheet); } } /** * 頭資訊校驗和處理 * @param headers */ private String[] headersHandler(String[] headers) { List<String> newHeaders = new ArrayList<String>(); for (String string : headers) { if (StringUtils.isNotBlank(string)) { newHeaders.add(string); } } int size = newHeaders.size(); return newHeaders.toArray(new String[size]); } /** * 4.寫入內容部分 * * @param hssfWorkbook {@link HSSFWorkbook} * @param hssfSheet {@link HSSFSheet} * @param headers 列標題,陣列形式, * 如{"列標題
[email protected]
@columnWidth","列標題[email protected]@columnWidth","列標題[email protected]@columnWidth"} * 其中引數@columnWidth可選,columnWidth為整型數值 * @param dataList 要匯出的資料集合 * @throws Exception */ private void writeContent(HSSFWorkbook hssfWorkbook, HSSFSheet hssfSheet, String[] headers, List<?> dataList) throws Exception { LOGGER.info("【寫入Excel內容部分】"); // 2015-8-13 增加,當沒有資料的時候,把原來拋異常的方式修改成返回一個只有頭資訊,沒有資料的空Excel if (CollectionUtils.isEmpty(dataList)) { LOGGER.warn("【沒有內容資料】"); return; } HSSFRow row = null; HSSFCell cell = null; // 單元格的值 Object cellValue = null; // 資料寫入行索引 int rownum = 2; // 單元格樣式 HSSFCellStyle cellStyle = createContentCellStyle(hssfWorkbook); // 遍歷集合,處理資料 for (int j = 0, size = dataList.size(); j < size; j++) { row = hssfSheet.createRow(rownum); for (int i = 0, len = headers.length; i < len; i++) { cell = row.createCell(i); cellValue = ReflectUtils.getCellValue(dataList.get(j), headers[i].split("@")[1]); cellValueHandler(cell, cellValue); cell.setCellStyle(cellStyle); } rownum++; } } /** * 設定列寬度 * @param i 列的索引號 * @param headInfo 表頭資訊,其中包含了使用者需要設定的列寬 */ private void setColumnWidth(int i, String[] headInfo, HSSFSheet hssfSheet) { if (headInfo.length < 3) { // 使用者沒有設定列寬,使用預設寬度 hssfSheet.setColumnWidth(i, DEFAUL_COLUMN_WIDTH); return; } if (StringUtils.isBlank(headInfo[2])) { // 使用預設寬度 hssfSheet.setColumnWidth(i, DEFAUL_COLUMN_WIDTH); return; } // 使用使用者設定的列寬進行設定 hssfSheet.setColumnWidth(i, Integer.parseInt(headInfo[2])); } /** * 單元格寫值處理器 * @param {{@link HSSFCell} * @param cellValue 單元格值 */ private void cellValueHandler(HSSFCell cell, Object cellValue) { // 2015-8-13 修改,判斷cellValue是否為空,否則在cellValue.toString()會出現空指標異常 if (cellValue == null) { cell.setCellValue(""); return; } if (cellValue instanceof String) { cell.setCellValue((String) cellValue); } else if (cellValue instanceof Boolean) { cell.setCellValue((Boolean) cellValue); } else if (cellValue instanceof Calendar) { cell.setCellValue((Calendar) cellValue); } else if (cellValue instanceof Double) { cell.setCellValue((Double) cellValue); } else if (cellValue instanceof Integer || cellValue instanceof Long || cellValue instanceof Short || cellValue instanceof Float) { cell.setCellValue((Double.parseDouble(cellValue.toString()))); } else if (cellValue instanceof HSSFRichTextString) { cell.setCellValue((HSSFRichTextString) cellValue); } cell.setCellValue(cellValue.toString()); } /** * 建立標題和表頭單元格樣式 * @param hssfWorkbook {@link HSSFWorkbook} * @return {@link HSSFCellStyle} */ private HSSFCellStyle createTitleCellStyle(HSSFWorkbook hssfWorkbook) { LOGGER.info("【建立標題和表頭單元格樣式】"); // 單元格的樣式 HSSFCellStyle cellStyle = hssfWorkbook.createCellStyle(); // 設定字型樣式,改為不變粗 HSSFFont font = hssfWorkbook.createFont(); font.setFontHeightInPoints((short) 13); font.setBoldweight(Font.BOLDWEIGHT_BOLD); cellStyle.setFont(font); // 單元格垂直居中 cellStyle.setVerticalAlignment(HSSFCellStyle.ALIGN_CENTER_SELECTION); // 設定通用的單元格屬性 setCommonCellStyle(cellStyle); return cellStyle; } /** * 建立內容單元格樣式 * @param hssfWorkbook {@link HSSFWorkbook} * @return {@link HSSFCellStyle} */ private HSSFCellStyle createContentCellStyle(HSSFWorkbook hssfWorkbook) { LOGGER.info("【建立內容單元格樣式】"); // 單元格的樣式 HSSFCellStyle cellStyle = hssfWorkbook.createCellStyle(); // 設定字型樣式,改為不變粗 HSSFFont font = hssfWorkbook.createFont(); font.setFontHeightInPoints((short) 11); cellStyle.setFont(font); // 設定單元格自動換行 cellStyle.setWrapText(true); // 單元格垂直居中 cellStyle.setVerticalAlignment(HSSFCellStyle.ALIGN_CENTER_SELECTION); //水平居中 // cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 設定通用的單元格屬性 setCommonCellStyle(cellStyle); return cellStyle; } /** * 設定通用的單元格屬性 * @param cellStyle 要設定屬性的單元格 */ private void setCommonCellStyle(HSSFCellStyle cellStyle) { // 居中 cellStyle.setAlignment(CellStyle.ALIGN_CENTER); // 設定邊框 cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN); cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN); cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN); } /** * 將生成的Excel輸出到指定目錄 * @param hssfWorkbook {@link HSSFWorkbook} * @param filePath 檔案輸出目錄,包括檔名(.xls) */ private void write2FilePath(HSSFWorkbook hssfWorkbook, String filePath) { LOGGER.info("【將生成的Excel輸出到指定目錄】filePath :" + filePath); FileOutputStream fileOut = null; try { fileOut = new FileOutputStream(filePath); hssfWorkbook.write(fileOut); } catch (Exception e) { LOGGER.error("【將生成的Excel輸出到指定目錄失敗】", e); throw new RuntimeException("將生成的Excel輸出到指定目錄失敗"); } finally { IOUtils.closeQuietly(fileOut); } } /** * 生成Excel,存放到指定目錄 * @param sheetName sheet名稱 * @param title 標題 * @param filePath 要匯出的Excel存放的檔案路徑 * @param headers 列標題,陣列形式, * 如{"列標題
[email protected]
@columnWidth","列標題[email protected]@columnWidth","列標題[email protected]@columnWidth"} * 其中引數@columnWidth可選,columnWidth為整型數值 * @param dataList 要匯出資料的集合 * @throws Exception */ public static void createExcel2FilePath(String sheetName, String title, String filePath, String[] headers, List<?> dataList) throws Exception { LOGGER.info("【生成Excel,並存放到指定資料夾目錄下】sheetName : " + sheetName + " , title : " + title + " , filePath : " + filePath + " , headers : " + JSONArray.fromObject(headers)); if (ArrayUtils.isEmpty(headers)) { LOGGER.warn("【表頭為空】"); throw new RuntimeException("表頭不能為空"); } PoiExcelUtils poiExcelUtil = new PoiExcelUtils(); // 1.建立 Workbook HSSFWorkbook hssfWorkbook = poiExcelUtil.getHSSFWorkbook(); // 2.建立 Sheet HSSFSheet hssfSheet = poiExcelUtil.getHSSFSheet(hssfWorkbook, sheetName); // 3.寫入 head poiExcelUtil.writeHeader(hssfWorkbook, hssfSheet, headers, title); // 4.寫入內容 poiExcelUtil.writeContent(hssfWorkbook, hssfSheet, headers, dataList); // 5.儲存檔案到filePath中 poiExcelUtil.write2FilePath(hssfWorkbook, filePath); } /** * 生成Excel的WorkBook,用於匯出Excel * @param sheetName sheet名稱 * @param title 標題 * @param headers 列標題,陣列形式, * 如{"列標題[email protected]@columnWidth","列標題[email protected]@columnWidth","列標題[email protected]@columnWidth"} * 其中引數@columnWidth可選,columnWidth為整型數值 * @param dataList 要匯出資料的集合 * @throws Exception */ public static HSSFWorkbook createExcel2Export(String sheetName, String title, String[] headers, List<?> dataList) throws Exception { LOGGER.info("【生成Excel的WorkBook,用於匯出Excel】sheetName : " + sheetName + " , title : " + title + " , headers : " + JSONArray.fromObject(headers)); if (ArrayUtils.isEmpty(headers)) { LOGGER.warn("【表頭為空】"); throw new RuntimeException("表頭不能為空"); } PoiExcelUtils poiExcelUtil = new PoiExcelUtils(); // 1.建立 Workbook HSSFWorkbook hssfWorkbook = poiExcelUtil.getHSSFWorkbook(); // 2.建立 Sheet HSSFSheet hssfSheet = poiExcelUtil.getHSSFSheet(hssfWorkbook, sheetName); // 3.寫入 head poiExcelUtil.writeHeader(hssfWorkbook, hssfSheet, headers, title); // 4.寫入內容 poiExcelUtil.writeContent(hssfWorkbook, hssfSheet, headers, dataList); return hssfWorkbook; } /** * 建立知識庫TOP3系統渠道統計的Excel資料 * @param sheetName sheet名稱 * @param title 標題 * @param headers 列標題,陣列形式, * 如{"列標題[email protected]@columnWidth","列標題[email protected]@columnWidth","列標題[email protected]@columnWidth"} * 其中引數@columnWidth可選,columnWidth為整型數值 * @param dataList 要匯出資料的集合 */ public static HSSFWorkbook createknowledgeTop3Excel(String sheetName, String title, String[] headers, List<List<?>> dataList) { LOGGER.info("【生成Excel的WorkBook,用於匯出Excel】sheetName : " + sheetName + " , title : " + title + " , headers : " + JSONArray.fromObject(headers)); if (ArrayUtils.isEmpty(headers)) { LOGGER.warn("【表頭為空】"); throw new RuntimeException("表頭不能為空"); } PoiExcelUtils poiExcelUtil = new PoiExcelUtils(); // 1.建立 Workbook HSSFWorkbook hssfWorkbook = poiExcelUtil.getHSSFWorkbook(); // 2.建立 Sheet HSSFSheet hssfSheet = poiExcelUtil.getHSSFSheet(hssfWorkbook, sheetName); // 3.寫入 head poiExcelUtil.writeHeader(hssfWorkbook, hssfSheet, headers, title); // 4.寫入內容 try { poiExcelUtil.writeComplexContent(hssfWorkbook, hssfSheet, headers, dataList); } catch (Exception e) { LOGGER.error("【寫入內容部分失敗】", e); throw new RuntimeException("寫入內容部分失敗"); } return hssfWorkbook; } /** * 生成內容部分(複雜內容,每列來自不同的資料集合) * @param hssfWorkbook {@link HSSFWorkbook} * @param hssfSheet {@link HSSFSheet} * @param headers 列標題,陣列形式, * 如{"列標題[email protected]@columnWidth","列標題[email protected]@columnWidth","列標題[email protected]@columnWidth"} * 其中引數@columnWidth可選,columnWidth為整型數值 * @param dataList 要匯出資料的集合 * @throws Exception */ private void writeComplexContent(HSSFWorkbook hssfWorkbook, HSSFSheet hssfSheet, String[] headers, List<List<?>> dataList) throws Exception { LOGGER.info("【寫入Excel內容部分】"); // 2015-8-13 增加,當沒有資料的時候,把原來拋異常的方式修改成返回一個只有頭資訊,沒有資料的空Excel if (CollectionUtils.isEmpty(dataList)) { LOGGER.warn("【沒有內容資料】"); return; } HSSFRow row = null; HSSFCell cell = null; // 單元格的值 Object cellValue = null; // 資料寫入行索引 int rownum = 2; // 單元格樣式 HSSFCellStyle cellStyle = createContentCellStyle(hssfWorkbook); // 遍歷集合,處理資料 // 要寫的內容的行數 int rows = dataList.get(0).size(); // 除去固定列“日期”外,還需要寫的列數 int columns = dataList.size(); /** * 思路說明 * 如果是top3,那麼dataList的長度應該是3(即除去固定列“日期”剩下的列數) * 其次索引依次是top1的資料、top2的資料、top3的資料 * top1/top2/top3的資料長度表示行數 * 第一層迴圈,肯定以行數為基準來進行 * 然後第一層迴圈的第一步是完成固定列的資料填充 * 第二步是填充對應行每個列的資料,而每個列的資料應該分別從top1、top2、top3中取 */ for (int j = 0; j < rows; j++) { row = hssfSheet.createRow(rownum); // 寫固定列“日期” cell = row.createCell(0); cellValue = ReflectUtils.getCellValue(dataList.get(0).get(j), headers[0].split("@")[1]); cellValueHandler(cell, cellValue); cell.setCellStyle(cellStyle); for (int i = 1; i <= columns; i++) { cell = row.createCell(i); cellValue = ReflectUtils.getCellValue(dataList.get(i - 1).get(j), headers[i].split("@")[1]); cellValueHandler(cell, cellValue); cell.setCellStyle(cellStyle); } rownum++; } } /** * 根據檔案路徑讀取excel檔案 * @param excelPath excel的路徑 * @param skipRows 需要跳過的行數 * @return List<String[]> 集合中每一個元素是一個數組,按單元格索引儲存每個單元格的值,一個元素可以封裝成一個需要的java bean * @throws Exception */ public static List<String[]> readExcel(String excelPath, int skipRows, int columCount) throws Exception { LOGGER.info("【讀取Excel】excelPath : " + excelPath + " , skipRows : " + skipRows); FileInputStream is = new FileInputStream(new File(excelPath)); POIFSFileSystem fs = new POIFSFileSystem(is); HSSFWorkbook wb = new HSSFWorkbook(fs); List<String[]> list = new ArrayList<String[]>(); HSSFSheet sheet = wb.getSheetAt(0); // 得到總共的行數 int rowNum = sheet.getPhysicalNumberOfRows(); try { for (int i = skipRows; i < rowNum; i++) { String[] vals = new String[columCount]; HSSFRow row = sheet.getRow(i); if (null == row) { continue; } for (int j = 0; j < columCount; j++) { HSSFCell cell = row.getCell(j); String val = getStringCellValue(cell); vals[j] = val; } list.add(vals); } } catch (Exception e) { LOGGER.error("【Excel解析失敗】", e); throw new RuntimeException("Excel解析失敗"); } finally { wb.close(); } return list; } /** * 獲取單元格資料內容為字串型別的資料 * * @param cell Excel單元格 * @return String 單元格資料內容 */ private static String getStringCellValue(HSSFCell cell) { if (cell == null) return ""; String strCell = ""; switch (cell.getCellType()) { case HSSFCell.CELL_TYPE_STRING: strCell = cell.getStringCellValue(); break; case HSSFCell.CELL_TYPE_NUMERIC: strCell = String.valueOf(format.format(cell.getNumericCellValue())).replace(",", ""); break; case HSSFCell.CELL_TYPE_BOOLEAN: strCell = String.valueOf(cell.getBooleanCellValue()); break; case HSSFCell.CELL_TYPE_BLANK: strCell = ""; break; default: strCell = ""; break; } if (strCell.equals("") || strCell == null) { return ""; } return strCell; } /** * 生成車票銷售總量統計表格 * @param sheetName sheet名稱 * @param title 標題 * @param headers 列標題,陣列形式, * 如{"列標題[email protected]@columnWidth","列標題[email protected]@columnWidth","列標題[email protected]@columnWidth"} * 其中引數@columnWidth可選,columnWidth為整型數值 * @param dataList 要匯出資料的集合 * @return {@link HSSFWorkbook} * @Author : luolin. create at 2015年12月22日 下午5:17:04 */ public static HSSFWorkbook createTicketReportExcel(String sheetName, String title, String[] headers, List<List<?>> dataList) { LOGGER.info("【生成車票銷售總量統計表格】sheetName : " + sheetName + " , title : " + title + " , headers : " + JSONArray.fromObject(headers)); if (ArrayUtils.isEmpty(headers)) { LOGGER.warn("【表頭為空】"); throw new RuntimeException("表頭不能為空"); } PoiExcelUtils poiExcelUtil = new PoiExcelUtils(); // 1.建立 Workbook HSSFWorkbook hssfWorkbook = poiExcelUtil.getHSSFWorkbook(); // 2.建立 Sheet HSSFSheet hssfSheet = poiExcelUtil.getHSSFSheet(hssfWorkbook, sheetName); // 3.寫入 head poiExcelUtil.writeHeader(hssfWorkbook, hssfSheet, headers, title); // 4.寫入內容 try { poiExcelUtil.writeComplexContent(hssfWorkbook, hssfSheet, headers, dataList); } catch (Exception e) { LOGGER.error("【寫入內容部分失敗】", e); throw new RuntimeException("寫入內容部分失敗"); } return hssfWorkbook; } }