Java 實現Excel匯入匯出(包含一些簡單樣式設定)工具類
阿新 • • 發佈:2019-02-01
最近很奇怪,客戶各種各樣奇葩的需求,匯出個表格設計各種樣式,真心無語,網上找了很多資料,新手就是這麼坑爹,找東西都不能有點速度!沒辦法,水平所致。提供給跟我差不多水平的朋友參考。
package com.cicro.fuchen.util.excel;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.hssf.util.HSSFColor.HSSFColorPredefined;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.cicro.fuchen.test.excel.ExcelException;
import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;
/**
* @author 墨竹
* @company cicro
* @date 2017年12月18日
* @time 上午9:35:39
* @since JDK1.8
* @todo Excel的匯入匯出工具類
*/
public class ExcelUtil<T> {
private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
/**
* @param headerMap
* Bena欄位與Excel題頭對應關係map(必須引數--Map(欄位名,表頭))
* @param columnWidth
* 匯出Excel的列寬(非必需)
* @param list
* 資料beanList(必須引數)
* @param fileName
* 檔名(必須引數 例"D:\\123.xls")
* @param sheetName
* Excel頁名(必須引數)
* @TODO 資料匯出到Excel表格
*/
public void exportToExcel(Map<String, String> headerMap, int[] columnWidth, List<T> list, String fileName,
String sheetName) {
if (list.size() <= 0) {
log.error("資料來源沒有資料");
return;
}
expExcel(headerMap, columnWidth, list, fileName, sheetName);
}
/**
* @param fileName
* 檔名(必須引數,完整路徑,如:"D:\\123.xls")
* @param sheetName
* Excel頁名(必須引數)
* @param entityClass
* Bean.class(必須引數)
* @param headerMap
* (必須引數)表頭與欄位對應關係(Map(表頭,欄位名))
* @return list
*
* @TODO 資料從Excel表格匯入到資料庫
*/
public List<T> importFromExcel(String fileName, String sheetName, Class<T> entityClass,
Map<String, String> headerMap) {
return impExcel(fileName, sheetName, entityClass, headerMap);
}
/**
* @param headerMap
* Bena欄位與Excel題頭對應關係map()
* @param columnWidth
* 匯出Excel的列寬
* @param list
* 資料beanList
* @param fileName
* 檔名
* @param sheetName
* Excel頁名
*/
@SuppressWarnings("resource")
private static <T> void expExcel(Map<String, String> headerMap, int[] columnWidth, List<T> list, String fileName,
String sheetName) {
// 宣告一個工作簿
HSSFWorkbook workbook = new HSSFWorkbook();
// 生成一個表格頁
HSSFSheet sheet = workbook.createSheet(sheetName);
// 生成一個表格樣式(表頭樣式)
HSSFCellStyle style1 = workbook.createCellStyle();
// 設定單元格背景樣式顏色
style1.setFillPattern(FillPatternType.SOLID_FOREGROUND);// 普通顏色填充
style1.setFillForegroundColor(HSSFColorPredefined.BLUE.getIndex());// 藍色背景
// 設定Excel中的邊框(表頭的邊框)
style1.setAlignment(HorizontalAlignment.CENTER);// 文字水平居中
style1.setVerticalAlignment(VerticalAlignment.CENTER);// 文字垂直居中
style1.setBorderBottom(BorderStyle.THIN);// 底部邊框線樣式(細實線)
style1.setBottomBorderColor(HSSFColorPredefined.BLACK.getIndex());// 底部邊框線顏色
style1.setBorderLeft(BorderStyle.THIN);// 左邊框線樣式(細實線)
style1.setLeftBorderColor(HSSFColorPredefined.BLACK.getIndex());// 左邊框線顏色
style1.setBorderRight(BorderStyle.THIN);// 右邊框線樣式(細實線)
style1.setRightBorderColor(HSSFColorPredefined.BLACK.getIndex());// 右邊框線顏色
style1.setBorderTop(BorderStyle.THIN);// 頂部邊框線樣式(細實線)
style1.setTopBorderColor(HSSFColorPredefined.BLACK.getIndex());// 頂部邊框線顏色
style1.setWrapText(true);// 自動換行
// 設定字型
HSSFFont font1 = workbook.createFont();// 生成一個字型樣式
font1.setFontHeightInPoints((short) 20); // 字型高度(大小)
font1.setFontName("楷體"); // 字型
font1.setColor(HSSFColorPredefined.BLACK.getIndex());
font1.setBold(true);// 加粗
style1.setFont(font1);// 把字型應用到當前樣式
// 生成一個表格樣式(列表樣式---非表頭)
HSSFCellStyle style2 = workbook.createCellStyle();
// 設定單元格背景樣式顏色
style2.setFillPattern(FillPatternType.SOLID_FOREGROUND);// 普通顏色填充
style2.setFillForegroundColor(HSSFColorPredefined.LIGHT_GREEN.getIndex());// 藍色背景
// 設定Excel中的邊框(表頭的邊框)
style2.setAlignment(HorizontalAlignment.CENTER);// 文字水平居中
style2.setVerticalAlignment(VerticalAlignment.CENTER);// 文字垂直居中
style2.setBorderBottom(BorderStyle.THIN);// 底部邊框線樣式(細實線)
style2.setBottomBorderColor(HSSFColorPredefined.BLACK.getIndex());// 底部邊框線顏色
style2.setBorderLeft(BorderStyle.THIN);// 左邊框線樣式(細實線)
style2.setLeftBorderColor(HSSFColorPredefined.BLACK.getIndex());// 左邊框線顏色
style2.setBorderRight(BorderStyle.THIN);// 右邊框線樣式(細實線)
style2.setRightBorderColor(HSSFColorPredefined.BLACK.getIndex());// 右邊框線顏色
style2.setBorderTop(BorderStyle.THIN);// 頂部邊框線樣式(細實線)
style2.setTopBorderColor(HSSFColorPredefined.BLACK.getIndex());// 頂部邊框線顏色
style2.setWrapText(true);// 自動換行
// 設定字型
HSSFFont font2 = workbook.createFont();// 生成一個字型樣式
font2.setFontHeightInPoints((short) 14); // 字型高度(大小)
font2.setFontName("宋體"); // 字型
font2.setColor(HSSFColorPredefined.BLACK.getIndex());
font2.setBold(true);// 加粗
style2.setFont(font2);// 把字型應用到當前樣式
FileOutputStream out;
try {
fillSheet(sheet, style1, style2, list, headerMap);
// 設定列寬
if (columnWidth.length > 0) {
for (int i = 0; i < columnWidth.length; i++) {
sheet.setColumnWidth(i, columnWidth[i]);
log.info("第" + i + "列-------------------列寬---------------------" + columnWidth[i]);
}
}
out = new FileOutputStream(fileName);
workbook.write(out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @param fileName
* 檔名(完整路徑,如:"D:\\123.xls")
* @param sheetName
* Excel頁名(必須引數)
* @param entityClass
* Bean.class
* @param headerMap
* 表頭與欄位對應關係(Map(表頭,欄位名))
* @return list
*/
private static <T> List<T> impExcel(String fileName, String sheetName, Class<T> entityClass,
Map<String, String> headerMap) {
// 定義要返回的list
List<T> resultList = new ArrayList<T>();
try {
// 根據Excel資料來源建立WorkBook
Workbook workbook = Workbook.getWorkbook(new File(fileName));
// 獲取工作表
Sheet sheet = workbook.getSheet(sheetName);
// 獲取工作表的有效行數
int realRows = 0;
for (int i = 0; i < sheet.getRows(); i++) {
int nullCols = 0;
for (int j = 0; j < sheet.getColumns(); j++) {
Cell currentCell = sheet.getCell(j, i);
if (currentCell == null || "".equals(currentCell.getContents().toString())) {
nullCols++;
}
}
if (nullCols == sheet.getColumns()) {
break;
} else {
realRows++;
}
}
// 如果Excel中沒有資料則提示錯誤
if (realRows <= 1) {
log.error("Excel檔案中沒有任何資料");
}
Cell[] firstRow = sheet.getRow(0);
String[] excelFieldNames = new String[firstRow.length];
// 獲取Excel中的列名
for (int i = 0; i < firstRow.length; i++) {
excelFieldNames[i] = firstRow[i].getContents().toString().trim();
}
// 判斷需要的欄位在Excel中是否都存在
boolean isExist = true;
List<String> excelFieldList = Arrays.asList(excelFieldNames);
for (String cnName : headerMap.keySet()) {
if (!excelFieldList.contains(cnName)) {
isExist = false;
break;
}
}
// 如果有列名不存在,則丟擲異常,提示錯誤
if (!isExist) {
log.error("Excel中缺少必要的欄位,或欄位名稱有誤");
}
// 將列名和列號放入Map中,這樣通過列名就可以拿到列號
LinkedHashMap<String, Integer> colMap = new LinkedHashMap<String, Integer>();
for (int i = 0; i < excelFieldNames.length; i++) {
colMap.put(excelFieldNames[i], firstRow[i].getColumn());
}
// 將sheet轉換為list
for (int i = 1; i < realRows; i++) {
// 新建要轉換的物件
T entity = entityClass.newInstance();
// 給物件中的欄位賦值
for (Entry<String, String> entry : headerMap.entrySet()) {
// 獲取中文欄位名
String cnNormalName = entry.getKey();
// 獲取英文欄位名
String enNormalName = entry.getValue();
// 根據中文欄位名獲取列號
int col = colMap.get(cnNormalName);
// 獲取當前單元格中的內容
String content = sheet.getCell(col, i).getContents().toString().trim();
// 給物件賦值
setFieldValueByName(enNormalName, content, entity);
}
log.info("新增第----------" + i + "--------條資料成功");
resultList.add(entity);
}
} catch (BiffException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return resultList;
}
/**************************** 私有輔助方法 ************************/
/**
* @param sheet
* Excel表格
* @param style1
* 表頭樣式
* @param style2
* 列表樣式
* @param list
* 資料來源
* @param fieldMap
* Bean欄位和表頭對應關係map
* @throws Exception
*/
private static <T> void fillSheet(HSSFSheet sheet, HSSFCellStyle style1, HSSFCellStyle style2, List<T> list,
Map<String, String> fieldMap) throws Exception {
// 定義存放英文欄位名和中文欄位名的陣列
String[] enFields = new String[fieldMap.size()];// 英文欄位名
String[] headers = new String[fieldMap.size()];// 中文題頭
// 填充陣列
int count = 0;
for (Entry<String, String> entry : fieldMap.entrySet()) {
enFields[count] = entry.getKey();
headers[count] = entry.getValue();
count++;
}
HSSFRow row = sheet.createRow(0);// 第一行(標題行)
// 填充第一行列表題頭
for (int i = 0; i < headers.length; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellStyle(style1);
HSSFRichTextString text = new HSSFRichTextString(headers[i]);
cell.setCellValue(text);
}
// 遍歷集合資料,產生資料行
Iterator<T> it = list.iterator();
int index = 0;
while (it.hasNext()) {
index++;
row = sheet.createRow(index);
T t = (T) it.next();
for (int i = 0; i < enFields.length; i++) {
HSSFCell cell = row.createCell(i);
cell.setCellStyle(style2);
Object objValue = getFieldValueByNameSequence(enFields[i], t);
String fieldValue = objValue == null ? "" : objValue.toString();
// 如果不是圖片資料,就利用正則表示式判斷textValue是否全部由數字組成
if (fieldValue != null) {
Pattern p = Pattern.compile("^\\d+(\\.\\d+)?$");
Matcher matcher = p.matcher(fieldValue);
if (matcher.matches()) {
// 是數字當作double處理
cell.setCellValue(Double.parseDouble(fieldValue));
} else {
cell.setCellValue(fieldValue);
}
}
}
}
setColumnAutoSize(sheet);
}
/**
* @MethodName : getFieldValueByNameSequence
* @Description : 根據帶路徑或不帶路徑的屬性名獲取屬性值
* 即接受簡單屬性名,如userName等,又接受帶路徑的屬性名,如student.department.name等
*
* @param fieldNameSequence
* 帶路徑的屬性名或簡單屬性名
* @param o
* 物件
* @return 屬性值
* @throws Exception
*/
private static Object getFieldValueByNameSequence(String fieldNameSequence, Object o) throws Exception {
Object value = null;
// 將fieldNameSequence進行拆分
String[] attributes = fieldNameSequence.split("\\.");
if (attributes.length == 1) {
value = getFieldValueByName(fieldNameSequence, o);
} else {
// 根據屬性名獲取屬性物件
Object fieldObj = getFieldValueByName(attributes[0], o);
String subFieldNameSequence = fieldNameSequence.substring(fieldNameSequence.indexOf(".") + 1);
value = getFieldValueByNameSequence(subFieldNameSequence, fieldObj);
}
return value;
}
/**
* @MethodName : getFieldValueByName
* @Description : 根據欄位名獲取欄位值
* @param fieldName
* 欄位名
* @param o
* 物件
* @return 欄位值
*/
private static Object getFieldValueByName(String fieldName, Object o) throws Exception {
Object value = null;
Field field = getFieldByName(fieldName, o.getClass());
if (field != null) {
field.setAccessible(true);
value = field.get(o);
} else {
throw new ExcelException(o.getClass().getSimpleName() + "類不存在欄位名 " + fieldName);
}
return value;
}
/**
* @MethodName : getFieldByName
* @Description : 根據欄位名獲取欄位
* @param fieldName
* 欄位名
* @param clazz
* 包含該欄位的類
* @return 欄位
*/
private static Field getFieldByName(String fieldName, Class<?> clazz) {
// 拿到本類的所有欄位
Field[] selfFields = clazz.getDeclaredFields();
// 如果本類中存在該欄位,則返回
for (Field field : selfFields) {
if (field.getName().equals(fieldName)) {
return field;
}
}
// 否則,檢視父類中是否存在此欄位,如果有則返回
Class<?> superClazz = clazz.getSuperclass();
if (superClazz != null && superClazz != Object.class) {
return getFieldByName(fieldName, superClazz);
}
// 如果本類和父類都沒有,則返回空
return null;
}
private static void setColumnAutoSize(HSSFSheet sheet) {
for (int i = 0; i < sheet.getRow(0).getPhysicalNumberOfCells(); i++) {
sheet.autoSizeColumn(i);// 自動設定列寬
}
}
/**
* @MethodName : setFieldValueByName
* @Description : 根據欄位名給物件的欄位賦值
* @param fieldName
* 欄位名
* @param fieldValue
* 欄位值
* @param o
* 物件
*/
private static void setFieldValueByName(String fieldName, Object fieldValue, Object o) throws Exception {
Field field = getFieldByName(fieldName, o.getClass());
if (field != null) {
field.setAccessible(true);
// 獲取欄位型別
Class<?> fieldType = field.getType();
// 根據欄位型別給欄位賦值
if (String.class == fieldType) {
field.set(o, String.valueOf(fieldValue));
} else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) {
field.set(o, Integer.parseInt(fieldValue.toString()));
} else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) {
field.set(o, Long.valueOf(fieldValue.toString()));
} else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) {
field.set(o, Float.valueOf(fieldValue.toString()));
} else if ((Short.TYPE == fieldType) || (Short.class == fieldType)) {
field.set(o, Short.valueOf(fieldValue.toString()));
} else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) {
field.set(o, Double.valueOf(fieldValue.toString()));
} else if (Character.TYPE == fieldType) {
if ((fieldValue != null) && (fieldValue.toString().length() > 0)) {
field.set(o, Character.valueOf(fieldValue.toString().charAt(0)));
}
} else if (Date.class == fieldType) {
field.set(o, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(fieldValue.toString()));
} else {
field.set(o, fieldValue);
}
} else {
log.error(o.getClass().getSimpleName() + "類不存在欄位名 " + fieldName);
}
}
}