溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

基于 POI 封裝 ExcelUtil 精簡(jiǎn)的 Excel 導(dǎo)入導(dǎo)出

發(fā)布時(shí)間:2020-08-03 23:10:35 來源:網(wǎng)絡(luò) 閱讀:333 作者:cyzshenzhen 欄目:編程語言

基于 POI 封裝 ExcelUtil 精簡(jiǎn)的 Excel 導(dǎo)入導(dǎo)出

本文是使用 org.apache.poi 進(jìn)行一次簡(jiǎn)單的封裝,適用于大部分 excel 導(dǎo)入導(dǎo)出功能。過程中可能會(huì)用到反射,如若有對(duì)于性能有極致強(qiáng)迫癥的同學(xué),看看就好。

由于 poi 本身只是針對(duì)于 excel 等office軟件的一個(gè)工具包,在一些常規(guī)的 excel 導(dǎo)入導(dǎo)出時(shí),還需要再做一次精簡(jiǎn)的封裝,簡(jiǎn)化代碼耦合。

一、現(xiàn)狀

本人經(jīng)歷過幾家公司的代碼封裝,導(dǎo)入導(dǎo)出一般存在下面的情況。

1.1 導(dǎo)入

  1. 傳入文件地址,返回 Sheet 對(duì)象,在業(yè)務(wù)代碼中進(jìn)行循環(huán)遍歷,做相對(duì)應(yīng)的類型轉(zhuǎn)換,業(yè)務(wù)處理(二零零幾年的代碼框架)
  2. 傳入文件地址,返回 List<String, Object> 的對(duì)象,外部直接做強(qiáng)轉(zhuǎn)
  3. 傳入文件地址,返回 List<String, String> 的對(duì)象,外部將字符串對(duì)象轉(zhuǎn)換為對(duì)應(yīng)的類型

總結(jié):如果只有上述的選擇,本人是比較傾向于第二種,畢竟對(duì)外層是非常友好的

1.2 導(dǎo)出

  1. 直接在邏輯代碼中進(jìn)行遍歷封裝sheet,傳入到生成file的方法中(二零零幾年的代碼框架)
  2. 先循環(huán)遍歷 List<Model> 對(duì)象,轉(zhuǎn)換為 List<Map<String, String>> 對(duì)象,帶上 fieldName 傳入到封裝好excel生成的方法中,內(nèi)部則使用 map.get() 方法操作
  3. 直接將 List<Model> 對(duì)象帶上 fieldName 傳入到封裝好excel生成的方法中,內(nèi)部將 Model 對(duì)象轉(zhuǎn)換為 JSONObject,然后使用 jsonObj.get() 方法操作
  4. 先將 List<Model> 轉(zhuǎn)換為 JSONArray ,帶上 fieldName 傳入到封裝好excel生成的方法中,內(nèi)部將 Model 對(duì)象轉(zhuǎn)換為 JSONObject,然后使用 jsonObj.get() 方法操作。(使用這種做法,據(jù)分析應(yīng)該是為了執(zhí)行 jsonConfig.registerJsonValueProcessor(Date.class, new JsonDateValueProcessor("yyyy-MM-dd HH:mm:ss")); 這行代碼,可能是為了解決日期類型格式問題)

總結(jié):如果只有上述的選擇,本人是比較傾向于第三種,第三種只遍歷一次,并且外部未做處理。但是按第四種模式來看,那么第三種模式還是會(huì)存在日期格式問題,這個(gè)我們后續(xù)再分析如何處理。

二、導(dǎo)入

2.1 方法定義

/**
* excel導(dǎo)入
* @param keys       字段名稱數(shù)組,如  ["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 循環(huán)處理模塊

// 遍歷該行所有列
for (short j = 0; j < cols; j++) {
    cell = row.getCell(j);
    if(null == cell) continue;  // 為空時(shí),下一列

    // 根據(jù)poi返回的類型,做相應(yīng)的get處理
    if(Cell.CELL_TYPE_STRING == cell.getCellType()) {
        value = cell.getStringCellValue();
    } else if(Cell.CELL_TYPE_NUMERIC == cell.getCellType()) {
        value = cell.getNumericCellValue();

        // 由于日期類型格式也被認(rèn)為是數(shù)值型,此處判斷是否是日期的格式,若時(shí),則讀取為日期類型
        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 分析

  1. 入口只需要傳入文件名稱,以及外部需要讀取的key即可
  2. 內(nèi)部處理,則針對(duì) 數(shù)值型、日期類型、字符串 類型已經(jīng)做了對(duì)應(yīng)處理,外部則直接進(jìn)行強(qiáng)轉(zhuǎn)對(duì)應(yīng)的類型即可

三、導(dǎo)出

3.1 方法定義

/**
* excel導(dǎo)出
* @param fileNamePath   導(dǎo)出的文件名稱
* @param sheetName  導(dǎo)出的sheet名稱
* @param list       數(shù)據(jù)集合
* @param titles     第一行表頭
* @param fieldNames 字段名稱數(shù)組
* @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 循環(huán)處理模塊

// 遍歷生成數(shù)據(jù)行,通過反射獲取字段的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) {   //  不存在該方法,查看父類是否存在。此處只支持一級(jí)父類,若想支持更多,建議使用while循環(huán)
            if(null != clazz.getSuperclass()) {
                method = clazz.getSuperclass().getDeclaredMethod(methodName);
            }
        }
        if(null == method) {
            throw new Exception(clazz.getName() + " don't have menthod --> " + methodName);
        }
        ret = null == method.invoke(t) ? null : 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("第三方手動(dòng)閥");
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 總結(jié)

  1. 入口主要是需要傳入 List<Model> 數(shù)據(jù)集合,以及 fieldNames 字段名稱
  2. 內(nèi)部處理,是直接通過反射獲得 get 方法的返回值,進(jìn)行強(qiáng)轉(zhuǎn)為字符串進(jìn)行導(dǎo)出
  3. 為了兼容繼承父類的一些共有字段的設(shè)計(jì),則加上了一層父類的方法讀取

四、關(guān)于日期類型導(dǎo)出處理

1.1 日期字段導(dǎo)出指定格式內(nèi)容

  1. 建議在 Model 類中,新增一個(gè)擴(kuò)展字段,并封裝一個(gè) get 方法,內(nèi)容則只是對(duì)原字段進(jìn)行轉(zhuǎn)換,導(dǎo)出時(shí),fieldName 則傳遞擴(kuò)展字段即可。如 createTime,示例如下:
private Date createTime;
private String createTimeStr;   // 擴(kuò)展字段

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 代碼下載

My Blog

blog.guijianpan.com

技術(shù)交流

基于 POI 封裝 ExcelUtil 精簡(jiǎn)的 Excel 導(dǎo)入導(dǎo)出

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI