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

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

time 類型 解析excel rom 統計表 pty reat iou 包括


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 列標題,數組形式,
     *                 如{"列標題1@beanFieldName1@columnWidth","列標題2@beanFieldName2@columnWidth","列標題3@beanFieldName3@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 列標題,數組形式,
     *                 如{"列標題1@beanFieldName1@columnWidth","列標題2@beanFieldName2@columnWidth","列標題3@beanFieldName3@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 列標題,數組形式,
     *                 如{"列標題1@beanFieldName1@columnWidth","列標題2@beanFieldName2@columnWidth","列標題3@beanFieldName3@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 列標題,數組形式,
     *                 如{"列標題1@beanFieldName1@columnWidth","列標題2@beanFieldName2@columnWidth","列標題3@beanFieldName3@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 列標題,數組形式,
     *                 如{"列標題1@beanFieldName1@columnWidth","列標題2@beanFieldName2@columnWidth","列標題3@beanFieldName3@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 列標題,數組形式,
     *                 如{"列標題1@beanFieldName1@columnWidth","列標題2@beanFieldName2@columnWidth","列標題3@beanFieldName3@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 列標題,數組形式,
     *                 如{"列標題1@beanFieldName1@columnWidth","列標題2@beanFieldName2@columnWidth","列標題3@beanFieldName3@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;
    }

}

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