在作業中經常會遇到操作excel的需求,對于格式簡單、統一的excel可以選擇EasyExcel來實作功能,很簡單方便;而對于復雜的excel檔案,如有各式各樣的合并單元格、表頭不固定、行列跟隨業務資料動態變化……格式變幻多端的檔案,easyExcel就顯得無能為力了,選擇poi就可以解決此問題了,
這里貼上在作業中解決問題時,自己封裝的工具類,方便大家查閱:
目錄
一、讀取Excel、寫入Excel檔案工具類
二、匯出Excel檔案的樣式設定工具類
三、寫入Excel簡單示例
一、讀取、寫入Excel工具類
注:poi版本為org.apache.poi:4.1.0
/**
* 工具類-使用poi讀取Excel
*/
@Slf4j
public class ExcelUtilByPOI {
private static final String EXCEL_XLS = "xls";
private static final String EXCEL_XLSX = "xlsx";
/**
* 讀取excel檔案中的全部表格
* 描述:適用于沒有單元格合并的excel,并且 (titleOfRow,titleOfColumn)位置為讀取內容的起始位置的情況
* 每一行構成一個map,key值是列標題,value是列值,沒有值的單元格其value值為null
* 回傳結果最外層list對應excel檔案,第二層Iterable對應sheet頁,第三層map對應sheet頁中一行
*
* @param filePath 檔案路徑
* @param sheetCnt 讀取的檔案中前sheetCnt個sheet資料,如果值為-1,則讀取所有的sheet,否則,讀取前sheetCnt個sheet的資料,
* @return
* @throws Exception
*/
public static List<List<Map<String, Object>>> readExcelWithFiexPos(String filePath, int titleInRow, int titleInColumn, int sheetCnt) throws IOException {
Workbook wb = null;
try {
List<List<Map<String, Object>>> excelData = new ArrayList<>();
if (filePath.endsWith(EXCEL_XLS) || filePath.endsWith(EXCEL_XLSX)) {
File file = new File(filePath);
wb = getWorkbook(file);
int sheetSize = sheetCnt == -1 ? wb.getNumberOfSheets() : sheetCnt;
//遍歷sheet
for (int i = 0; i < sheetSize; i++) {
Sheet sheet = wb.getSheetAt(i);
List<Map<String, Object>> theSheetData = readSheet(sheet, titleInRow, titleInColumn);
excelData.add(theSheetData);
}
} else {
log.error("讀取的不是Excel檔案");
}
return excelData;
} catch (FileNotFoundException e) {
throw e;
} finally {
if (wb != null) {
wb.close();
}
}
}
/**
* 讀取excel檔案中的全部表格
* 描述:適用于沒有單元格合并的excel,并且 以fiexedValue在sheet中的位置為讀取內容起始位置的情況
* 每一行構成一個map,key值是列標題,value是列值,沒有值的單元格其value值為null
* 回傳結果最外層list對應excel檔案,第二層Iterable對應sheet頁,第三層map對應sheet頁中一行
*
* @param fixedValue 固定值(第一個列標題)
* @param filePath 檔案路徑
* @param sheetCnt 讀取的檔案中前sheetCnt個sheet資料,如果值為-1,則讀取所有的sheet,否則,讀取前sheetCnt個sheet的資料,
* @return
* @throws Exception
*/
public static List<List<Map<String, Object>>> readExcelWithFiexedTitle(String filePath, String fixedValue, int sheetCnt) throws IOException {
Workbook wb = null;
try {
List<List<Map<String, Object>>> excelData = new ArrayList<>();
if (filePath.endsWith(EXCEL_XLS) || filePath.endsWith(EXCEL_XLSX)) {
File file = new File(filePath);
wb = getWorkbook(file);
int sheetSize = sheetCnt == -1 ? wb.getNumberOfSheets() : sheetCnt;
//遍歷sheet
for (int i = 0; i < sheetSize; i++) {
Sheet sheet = wb.getSheetAt(i);
List<Integer> posForSheet = readPosForValue(sheet, fixedValue);
List<Map<String, Object>> theSheetData = readSheet(sheet, posForSheet.get(0), posForSheet.get(1));
excelData.add(theSheetData);
}
} else {
log.error("讀取的不是Excel檔案");
}
return excelData;
} catch (FileNotFoundException e) {
throw e;
} finally {
if (wb != null) {
wb.close();
}
}
}
/**
* 讀取excel檔案個sheet第rowNum行的內容,從firstColNum列開始往后讀取到第lastColNum列
*
* @param filePath
* @param rowNum
* @param firstColNum
* @param lastColNum
* @return
*/
public static List<List<Object>> readRowData(String filePath, int rowNum, int firstColNum, int lastColNum) throws IOException {
List<List<Object>> dataList = new ArrayList<>();
File file = new File(filePath);
Workbook wb = getWorkbook(file);
int sheetCnt = wb.getNumberOfSheets();
for (int cnt = 0; cnt < sheetCnt; cnt++) { //遍歷每一個sheet
Sheet sheet = wb.getSheetAt(cnt);
Row row = sheet.getRow(rowNum);
lastColNum = lastColNum == -1 ? row.getLastCellNum() : lastColNum; //如果沒有lastColNum則為其值為最后一列
List<Object> sheetContentList = new ArrayList<>();
Cell cell = null;
String value = null;
for (int i = firstColNum; i < lastColNum; i++) { //讀取指定行的內容
cell = row.getCell(i);
value = readCellByType(cell);
sheetContentList.add(value);
}
dataList.add(sheetContentList);
}
return dataList;
}
/**
* 讀取給定sheet的內容
* 描述:
* 讀取excel檔案中的指定名稱的表格 用于沒有單元格合并的表格,且 (titleOfRow,titleOfColumn)位置為讀取內容的起始位置的情況
* 每一行構成一個map(key值是列標題,value是列值),沒有值的單元格其value值為null,
* 回傳結果最外層的list對應一個sheet頁,第二層的map對應sheet頁中的一行,
*
* @param sheet
* @return
*/
private static List<Map<String, Object>> readSheet(Sheet sheet, int titleInRow, int titleInColumn) {
List<Map<String, Object>> sheetList = null;
sheetList = new ArrayList<Map<String, Object>>();
List<String> titles = new ArrayList<>();
int rowSize = sheet.getLastRowNum() + 1;
for (int i = titleInRow; i < rowSize; i++) {
Row row = sheet.getRow(i);
if (row == null)
continue;
;//略過空行
int cellSize = row.getLastCellNum();
if (i == titleInRow) //標題行
{
for (int j = titleInColumn; j < cellSize; j++) {
Cell cell = row.getCell(j);
if (cell != null) {
titles.add(cell.toString());
}
}
} else { //對應每一行的資料
Map<String, Object> rowDataMap = new LinkedHashMap<>();
for (int j = titleInColumn; j < titleInColumn + titles.size(); j++) {
Cell cell = row.getCell(j);
String value = null;
CellType cellType = null;
if (cell == null) {
continue;
}
cellType = cell.getCellTypeEnum();
switch (cellType) {
case STRING:
// value = cell.getRichStringCellValue().getString();
value = cell.getStringCellValue();
break;
case NUMERIC: //包含日期和普通數字
if (DateUtil.isCellDateFormatted(cell)) {
Date date = cell.getDateCellValue();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
value = df.format(date);
} else {
double cellValue = cell.getNumericCellValue();
value = String.valueOf(cellValue);
// 下面的代碼,會自動舍棄讀取單元格中顯示的值(可能是做了round()之后的結果),不是單元格中最原本的值
/*NumberFormat nf = NumberFormat.getInstance();
String tmpValue = nf.format(cell.getNumericCellValue());
if (tmpValue.indexOf(",") >= 0) {
tmpValue = tmpValue.replaceAll(",", "");
}
value = tmpValue;*/
}
break;
case FORMULA:
// cell.getCellFormula();
cell.setCellType(CellType.STRING);
value = cell.getStringCellValue();
break;
case BOOLEAN:
value = String.valueOf(cell.getBooleanCellValue());
break;
default:
if (cell != null) {
value = cell.toString();
}
}
String key = titles.get(j - titleInColumn);
rowDataMap.put(key, value);
}
sheetList.add(rowDataMap);
}
}
return sheetList;
}
/**
* 讀取sheet中指定值的位置
*
* @param sheet
* @return
*/
private static List<Integer> readPosForValue(Sheet sheet, String fixedValue) {
List<Integer> posList = new ArrayList();
Object value = null;
for (int j = 0; j < sheet.getPhysicalNumberOfRows(); j++) { // 獲取每行
XSSFRow row = (XSSFRow) sheet.getRow(j);
if (row != null) {
for (int k = 0; k < sheet.getRow(0).getPhysicalNumberOfCells(); k++) { // 獲取每個單元格
Cell cell = row.getCell(k);
if (cell == null) {
continue;
}
CellType cellTypeEnum = cell.getCellTypeEnum();
switch (cellTypeEnum) {
case STRING:
value = cell.getRichStringCellValue().getString();
break;
// case Cell.CELL_TYPE_NUMERIC:
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
value = cell.getDateCellValue();
} else {
double cellValue = cell.getNumericCellValue();
value = String.valueOf(cellValue);
/* // 下面的代碼,會自動舍棄讀取單元格中顯示的值(可能是做了round()之后的結果),不是單元格中最原本的值
NumberFormat nf = NumberFormat.getInstance();
String tmpValue = nf.format(cell.getNumericCellValue());
if (tmpValue.indexOf(",") >= 0) {
tmpValue = tmpValue.replaceAll(",", "");
}
value = tmpValue;*/
}
break;
case BOOLEAN:
value = cell.getBooleanCellValue();
break;
case FORMULA:
value = cell.getCellFormula();
break;
default:
value = "";
break;
}
if (fixedValue.equals(value.toString())) {
posList.add(cell.getRowIndex());
posList.add(cell.getColumnIndex());
break;
}
}
}
if (!BeanUtil.isEmpty(posList)) {
break;
}
}
return posList;
}
/**
* 根據excel的版本,獲取相應的Workbook
*
* @param file
* @return
*/
public static Workbook getWorkbook(File file) throws IOException {
Workbook wb = null;
InputStream fis = new FileInputStream(file);
if (file.getName().endsWith(EXCEL_XLS)) //2003
{
wb = new HSSFWorkbook(fis);
} else if (file.getName().endsWith(EXCEL_XLSX)) {
wb = new XSSFWorkbook(fis);//2007 2010
}
if (fis != null) {
fis.close();
}
return wb;
}
/**
* 判斷指定的單元格是否是合并單元格
*
* @param sheet
* @param row 行下標
* @param column 列下標
* @return
*/
public static boolean isMergedRegion(Sheet sheet, int row, int column) {
int sheetMergeCount = sheet.getNumMergedRegions();
for (int i = 0; i < sheetMergeCount; i++) {
CellRangeAddress range = sheet.getMergedRegion(i);
int firstColumn = range.getFirstColumn();
int lastColumn = range.getLastColumn();
int firstRow = range.getFirstRow();
int lastRow = range.getLastRow();
if (row >= firstRow && row <= lastRow) {
if (column >= firstColumn && column <= lastColumn) {
return true;
}
}
}
return false;
}
/**
* 獲取合并單元格的值
*
* @param sheet
* @param row
* @param column
* @return
*/
public static String getMergedCellValue(Sheet sheet, int row, int column) {
String value = null;
int mergedCellCnt = sheet.getNumMergedRegions();
for (int i = 0; i < mergedCellCnt; i++) {
CellRangeAddress mergedCell = sheet.getMergedRegion(i);
int firstColumn_pos = mergedCell.getFirstColumn();
int lastColumn_pos = mergedCell.getLastColumn();
int firstRow_pos = mergedCell.getFirstRow();
int lastRow_pos = mergedCell.getLastRow();
if (row >= firstRow_pos && row <= lastRow_pos) {
if (column >= firstColumn_pos && column <= lastColumn_pos) {
Row firstRow = sheet.getRow(firstRow_pos);
Cell cell = firstRow.getCell(firstColumn_pos);
if (cell == null) {
continue;
}
CellType cellType = cell.getCellTypeEnum();
switch (cellType) {
case STRING:
// value = cell.getRichStringCellValue().getString();
value = cell.getStringCellValue();
break;
case NUMERIC: //包含日期和普通數字
if (DateUtil.isCellDateFormatted(cell)) {
Date date = cell.getDateCellValue();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
value = df.format(date);
} else {
double cellValue = cell.getNumericCellValue();
value = String.valueOf(cellValue);
/* 下面的代碼,會自動舍棄讀取單元格中顯示的值(可能是做了round()之后的結果),不是單元格中最原本的值
NumberFormat nf = NumberFormat.getInstance();
String tmpValue = nf.format(cell.getNumericCellValue());
if (tmpValue.indexOf(",") >= 0) {
tmpValue = tmpValue.replaceAll(",", "");
}
value = tmpValue;*/
}
break;
case FORMULA:
// cell.getCellFormula();
cell.setCellType(CellType.STRING);
value = cell.getStringCellValue();
break;
case BOOLEAN:
value = String.valueOf(cell.getBooleanCellValue());
break;
default:
if (cell != null) {
value = cell.toString();
}
}
return cell == null || value == null ? "" : value;
}
}
}
return null;
}
/**
* 讀取單元格的型別
*
* @param cell
* @return
*/
public static String readCellByType(Cell cell) {
if (cell == null) {
return null;
}
CellType cellType = cell.getCellTypeEnum();
String value = null;
switch (cellType) {
case STRING:
// value = cell.getRichStringCellValue().getString();
value = cell.getStringCellValue();
break;
case NUMERIC: //包含日期和普通數字
if (DateUtil.isCellDateFormatted(cell)) {
Date date = cell.getDateCellValue();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
value = df.format(date);
} else {
double cellValue = cell.getNumericCellValue();
value = String.valueOf(cellValue);
/* 下面的代碼,會自動舍棄讀取單元格中顯示的值(可能是做了round()之后的結果),不是單元格中最原本的值
NumberFormat nf = NumberFormat.getInstance();
String tmpValue = nf.format(cell.getNumericCellValue());
if (tmpValue.indexOf(",") >= 0) {
tmpValue = tmpValue.replaceAll(",", "");
}
value = tmpValue;*/
}
break;
case FORMULA:
// cell.getCellFormula();
cell.setCellType(CellType.STRING);
value = cell.getStringCellValue();
break;
case BOOLEAN:
value = String.valueOf(cell.getBooleanCellValue());
break;
default:
if (cell != null) {
value = cell.toString();
}
}
return cell == null || value == null ? "" : value;
}
/**
* 讀取一個excel檔案中所有的sheet名字串列
*
* @param filePath 檔案路徑
* @return
* @throws Exception
*/
public static List<String> readSheetNames(String filePath) throws Exception {
Workbook wb = null;
List<String> sheetNames = new ArrayList<String>();
try {
if (filePath.endsWith(EXCEL_XLS) || filePath.endsWith(EXCEL_XLSX)) {
// 讀取Excel檔案
File file = new File(filePath);
wb = getWorkbook(file);
int sheetSize = wb.getNumberOfSheets();
// 遍歷sheet頁
for (int i = 0; i < sheetSize; i++) {
Sheet sheet = wb.getSheetAt(i);
sheetNames.add(sheet.getSheetName());
}
} else {
throw new BaseException(EPowerResultCode.JUDGE_EXCEL_FILE);
}
return sheetNames;
} catch (FileNotFoundException e) {
log.error(e.getMessage());
throw e;
} finally {
if (wb != null) {
wb.close();
}
}
}
/**
* 讀取excel中所有sheet的標題
*
* @return
*/
public static List<String> readSheetTitles(String filePath) throws Exception {
Workbook wb = null;
List<String> titleList = new ArrayList<String>();
try {
if (filePath.endsWith(EXCEL_XLS) || filePath.endsWith(EXCEL_XLSX)) {
// 讀取Excel檔案
File file = new File(filePath);
wb = getWorkbook(file);
int sheetSize = wb.getNumberOfSheets();
for (int i = 0; i < sheetSize; i++) {
Sheet sheet = wb.getSheetAt(i);
Row row = sheet.getRow(0);//默認第一行為表頭
short lastCellNum = row.getLastCellNum();//共有多少列
for (int j = 0; j < lastCellNum; j++) {
Cell cell = row.getCell(j);
titleList.add(cell.getStringCellValue().trim());
}
}
}
return titleList;
} catch (Exception e) {
log.error(e.getMessage());
throw e;
} finally {
if (wb != null) {
wb.close();
}
}
}
/**
* 匯出檔案
* @param request
* @param response
* @param wb
* @param fileName
*/
public static void exportFile(HttpServletRequest request, HttpServletResponse response, Workbook wb, String fileName) throws Exception{
String userAgent = request.getHeader("USER-AGENT");
if (userAgent.contains("MSIE")) {// IE瀏覽器
fileName = URLEncoder.encode(fileName, "UTF8");
} else if (userAgent.contains("Mozilla")) {// google,火狐瀏覽器
fileName = new String(fileName.getBytes(), "ISO8859-1");
} else {
fileName = URLEncoder.encode(fileName, "UTF8");// 其他瀏覽器
}
response.setContentType("application/octet-stream;charset=UTF-8");
response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
OutputStream outputStream = response.getOutputStream();
wb.write(outputStream);
}
}
二、Excel樣式設定工具類
/**
* 匯出的Excel單元格樣式設定
*/
public class ExcelStyleUtil {
/**
* 表頭字體
*
* @return
*/
public static Font headerFoot(Workbook wb) {
Font headerFont = wb.createFont();
headerFont.setFontName("微軟雅黑");
headerFont.setFontHeightInPoints((short) 13);
headerFont.setBold(true);
// headerFont.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());
headerFont.setColor(IndexedColors.BLACK.getIndex());
return headerFont;
}
/**
* 正文字體
*
* @param wb
* @return
*/
public static Font contextFont(Workbook wb) {
Font contextFont = wb.createFont();
contextFont.setFontName("微軟雅黑");
contextFont.setFontHeightInPoints((short) 13);
contextFont.setBold(false);
contextFont.setColor(IndexedColors.BLACK.getIndex());
// contextFont.setColor(HSSFColor.HSSFColorPredefined.BLACK.getIndex());
return contextFont;
}
/**
* 表頭樣式-左右上下居中
*
* @param wb
* @return
*/
public static CellStyle headerStyle(Workbook wb) {
CellStyle headerStyle = wb.createCellStyle();
Font font = headerFoot(wb);
headerStyle.setFont(font);
headerStyle.setAlignment(HorizontalAlignment.CENTER);//水平居中
headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中
headerStyle.setLocked(true);//鎖定
headerStyle.setWrapText(false);// 自動換行
headerStyle.setBorderBottom(BorderStyle.THIN);//下邊框
headerStyle.setBorderTop(BorderStyle.THIN);//上邊框
headerStyle.setBorderLeft(BorderStyle.THIN);//左
headerStyle.setBorderRight(BorderStyle.THIN);//右
return headerStyle;
}
/**
* 單元格樣式 - 水平、垂直居中
*
* @param wb
* @return
*/
public static CellStyle contextAlignCenterStyle(Workbook wb) {
CellStyle style = wb.createCellStyle();
Font font = contextFont(wb);
style.setFont(font);
style.setAlignment(HorizontalAlignment.CENTER);//水平居中
style.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中
style.setLocked(true);
style.setWrapText(true);// 自動換行
style.setBorderBottom(BorderStyle.THIN);//下邊框
style.setBorderTop(BorderStyle.THIN);//上邊框
style.setBorderLeft(BorderStyle.THIN);//左
style.setBorderRight(BorderStyle.THIN);//右
return style;
}
/**
* 單元格樣式-無左邊框
* @param wb
* @return
*/
public static CellStyle contextNoLeftBorder(Workbook wb){
CellStyle style = wb.createCellStyle();
Font font = contextFont(wb);
style.setFont(font);
style.setAlignment(HorizontalAlignment.CENTER);//水平居中
style.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中
style.setLocked(true);
style.setWrapText(true);// 自動換行
style.setBorderBottom(BorderStyle.THIN);//下邊框
style.setBorderTop(BorderStyle.THIN);//上邊框
style.setBorderRight(BorderStyle.THIN);//右
return style;
}
/**
* 單元格樣式-無左右邊框
* @param wb
* @return
*/
public static CellStyle contextNoLeftRightBorder(Workbook wb){
CellStyle style = wb.createCellStyle();
Font font = contextFont(wb);
style.setFont(font);
style.setAlignment(HorizontalAlignment.CENTER);//水平居中
style.setVerticalAlignment(VerticalAlignment.CENTER);//垂直居中
style.setLocked(true);
style.setWrapText(true);// 自動換行
style.setBorderBottom(BorderStyle.THIN);//下邊框
style.setBorderTop(BorderStyle.THIN);//上邊框
return style;
}
}
三、寫入Excel簡單示例
public void testWriteExcel(HttpServletRequest request, HttpServletResponse response){
//1.創建book
Workbook wb = new XSSFWorkbook();
Sheet sheet = wb.createSheet("sheet名稱,可為空");
//2.創建sheet
sheet.createFreezePane(1, 2, 0, 0);//凍結首列和前兩行
CellStyle headerStyle = ExcelStyleUtil.headerStyle(wb);
//3.創建行
Row row0 = sheet.createRow(0);
//4.創建單元格
Cell cell00 = row0.createCell(0);
cell00.setCellStyle(headerStyle);//設定單元格樣式
cell00.setCellValue("單元格值");
CellRangeAddress mergeReion = new CellRangeAddress(0, 0, 0, 2);
sheet.addMergedRegion(mergeReion);//合并首行的前兩個單元格
//(1)第二行設定表頭
Row row1 = sheet.createRow(1);
for (int i = 0; i < titles.size(); i++) {
Object title = titles.get(i);
Cell cell1i = row1.createCell(i);
cell1i.setCellValue(String.valueOf(title));
cell1i.setCellStyle(headerStyle);
}
//(2)下面設定表體資料:創建10行3列的表體
CellStyle contextStyle = ExcelStyleUtil.contextAlignCenterStyle(wb);//內容樣式
for (int i = 0; i < 10; i++) {
Row rowi = sheet.createRow(i + 2);
for(int j=0;j<3;j++){
Cell cellij = rowi.createCell(j);
cellij.setCellValue("單元格值");
sheet.setColumnWidth(j,5000);//設定列寬
cellij.setCellStyle(contextStyle);
}
}
//(3)匯出到瀏覽器
try{
ExcelUtilByPOI.exportFile(request,response,wb,"檔案名");//呼叫工具方法
}catch (Exception e){
throw new BaseException(EPowerResultCode.DOWNLOAD_FILE_FAIL);
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/333718.html
標籤:其他
