基於 POI 封裝 ExcelUtil 精簡的 Excel 匯入匯出
阿新 • • 發佈:2019-01-09
由於 poi 本身只是針對於 excel 等office軟體的一個工具包,在一些常規的 excel 匯入匯出時,還需要再做一次精簡的封裝,簡化程式碼耦合。
一、現狀
本人經歷過幾家公司的程式碼封裝,匯入匯出一般存在下面的情況。
1.1 匯入
- 傳入檔案地址,返回 Sheet 物件,在業務程式碼中進行迴圈遍歷,做相對應的型別轉換,業務處理(二零零幾年的程式碼框架)
- 傳入檔案地址,返回 List<String, Object> 的物件,外部直接做強轉
- 傳入檔案地址,返回 List<String, String> 的物件,外部將字串物件轉換為對應的型別
總結:如果只有上述的選擇,本人是比較傾向於第二種,畢竟對外層是非常友好的
1.2 匯出
- 直接在邏輯程式碼中進行遍歷封裝sheet,傳入到生成file的方法中(二零零幾年的程式碼框架)
- 先迴圈遍歷 List<Model> 物件,轉換為 List<Map<String, String>> 物件,帶上 fieldName 傳入到封裝好excel生成的方法中,內部則使用 map.get() 方法操作
- 直接將 List<Model> 物件帶上 fieldName 傳入到封裝好excel生成的方法中,內部將 Model 物件轉換為 JSONObject,然後使用 jsonObj.get() 方法操作
- 先將 List<Model> 轉換為 JSONArray ,帶上 fieldName 傳入到封裝好excel生成的方法中,內部將 Model 物件轉換為 JSONObject,然後使用 jsonObj.get() 方法操作。(使用這種做法,據分析應該是為了執行 jsonConfig.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor(“yyyy-MM-dd HH:mm:ss”)); 這行程式碼,可能是為了解決日期型別格式問題)
總結:如果只有上述的選擇,本人是比較傾向於第三種,第三種只遍歷一次,並且外部未做處理。但是按第四種模式來看,那麼第三種模式還是會存在日期格式問題,這個我們後續再分析如何處理。
二、匯入
2.1 方法定義
/** * excel匯入 * @param keys 欄位名稱陣列,如 ["id", "name", ... ] * @param filePath 檔案實體地址 * @return * @author yzChen * @date 2016年12月18日 下午2:46:51 */ public static List<Map<String, Object>> imp(String filePath, String[] keys) throws Exception {}
2.2 迴圈處理模組
// 遍歷該行所有列
for (short j = 0; j < cols; j++) {
cell = row.getCell(j);
if(null == cell) continue; // 為空時,下一列
// 根據poi返回的型別,做相應的get處理
if(Cell.CELL_TYPE_STRING == cell.getCellType()) {
value = cell.getStringCellValue();
} else if(Cell.CELL_TYPE_NUMERIC == cell.getCellType()) {
value = cell.getNumericCellValue();
// 由於日期型別格式也被認為是數值型,此處判斷是否是日期的格式,若時,則讀取為日期型別
if(cell.getCellStyle().getDataFormat() > 0) {
value = cell.getDateCellValue();
}
} else if(Cell.CELL_TYPE_BOOLEAN == cell.getCellType()) {
value = cell.getBooleanCellValue();
} else if(Cell.CELL_TYPE_BLANK == cell.getCellType()) {
value = cell.getDateCellValue();
} else {
throw new Exception("At row: %s, col: %s, can not discriminate type!");
}
map.put(keys[j], value);
}
2.3 使用
String filePath = "E:/order.xls";
String[] keys = new String[]{"id","brand"};
List<Map<String, Object>> impList;
try {
impList = ExcelUtil.imp(filePath, keys);
for (Map<String, Object> map : impList) {
System.out.println(map.get("brand"));
}
} catch (Exception e) {
e.printStackTrace();
}
2.4 分析
- 入口只需要傳入檔名稱,以及外部需要讀取的key即可
- 內部處理,則針對 數值型、日期型別、字串 型別已經做了對應處理,外部則直接進行強轉對應的型別即可
三、匯出
3.1 方法定義
/**
* excel匯出
* @param fileNamePath 匯出的檔名稱
* @param sheetName 匯出的sheet名稱
* @param list 資料集合
* @param titles 第一行表頭
* @param fieldNames 欄位名稱陣列
* @return
* @throws Exception
* @author yzChen
* @date 2017年5月6日 下午3:53:47
*/
public static <T> File export(String fileNamePath, String sheetName,
List<T> list, String[] titles, String[] fieldNames) throws Exception {}
3.2 迴圈處理模組
// 遍歷生成資料行,通過反射獲取欄位的get方法
for (int i = 0; i < list.size(); i++) {
t = list.get(i);
HSSFRow row = sheet.createRow(i+1);
Class<? extends Object> clazz = t.getClass();
for(int j = 0; j < fieldNames.length; j++){
methodName = "get" + capitalize(fieldNames[j]);
try {
method = clazz.getDeclaredMethod(methodName);
} catch (java.lang.NoSuchMethodException e) { // 不存在該方法,檢視父類是否存在。此處只支援一級父類,若想支援更多,建議使用while迴圈
if(null != clazz.getSuperclass()) {
method = clazz.getSuperclass().getDeclaredMethod(methodName);
}
}
if(null == method) {
throw new Exception(clazz.getName() + " don't have menthod --> " + methodName);
}
ret = method.invoke(t);
setCellGBKValue(row.createCell(j), ret + "");
}
}
3.3 使用
String[] titles = new String[]{"Id", "Brand"};
String[] fieldNames = new String[]{"id", "brand"};
List<Order> expList = new ArrayList<Order>();
Order order = new Order();
order.setId(1L);
order.setBrand("第三方手動閥");
expList.add(order);
order = new Order();
order.setId(2L);
order.setBrand("scsdsad");
expList.add(order);
String fileNamePath = "E:/order.xls";
try {
ExcelUtil.export(fileNamePath, "訂單", expList, titles, fieldNames);
} catch (Exception e) {
e.printStackTrace();
}
3.4 總結
- 入口主要是需要傳入 List<Model> 資料集合,以及 fieldNames 欄位名稱
- 內部處理,是直接通過反射獲得 get 方法的返回值,進行強轉為字串進行匯出
- 為了相容繼承父類的一些共有欄位的設計,則加上了一層父類的方法讀取
四、關於日期型別匯出處理
1.1 日期欄位匯出指定格式內容
- 建議在 Model 類中,新增一個擴充套件欄位,並封裝一個 get 方法,內容則只是對原欄位進行轉換,匯出時,fieldName 則傳遞擴充套件欄位即可。如 createTime,示例如下:
private Date createTime; private String createTimeStr; // 擴充套件欄位
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getCreateTimeStr() {
createTimeStr = DateUtil.formatDatetime(this.createTime);
return createTimeStr;
}
## 五、Demo下載
[GJP-Example-ExcelUtil 程式碼下載](https://pan.baidu.com/s/1jIzFFPO)