使用POI做的一個生成Excel的工具類。包含了匯出Excel和解析Excel方法
阿新 • • 發佈:2019-01-06
/**
*
*/
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;
}
}