java批量導入excel數據「java實現excel導入」

Java不固定列excel導入導出

看完本文,你一定會有所收穫

一、介紹

在上篇文章中,我們簡單的介紹了 excel 導入導出技術實踐方案,就目前而已,使用最多的開源框架主要有以下三類,分別是:

  • apache poi:poi是使用最廣的一種導入導出框架,但是缺點也很明顯,導出大數據量的時候,容易oom
  • easypoi:easypoi 的底層也是基於 apache poi 進行深度開發的,它主要的特點就是將更多重複的工作,全部簡單化,避免編寫重複的代碼,最顯著的特點就是導出的支持非常豐富
  • easyexcel:easyexcel 是阿里巴巴開源的一款 excel 解析工具,底層邏輯也是基於 apache poi 進行二次開發的,目前的應用也非常廣

總的來說,easypoi 和 easyexcel 都是基於apache poi進行二次開發的。

不同點在於:

1、easypoi 在讀寫數據的時候,優先是先將數據寫入內存,因此讀寫性能非常高,這種操作平時使用的時候不會出現什麼問題,但是當數據量很大的時候,會出現 oom,當然它也提供了 sax 模式一行一行解析,需要自己根據當前場景來實現。

2、easyexcel 默認基於 sax 模式一行一行解析,明顯降低了內存,不會出現 oom 情況,程序有過高並發場景的驗證,因此整體運行比較穩定,相對於 easypoi 來說,讀寫性能稍慢!

3、easypoi 的 api 非常豐富,easyexcel 功能的支持,比較簡單。

就小編的實際使用情況來看,easypoi 相比 easyexcel 而言,有很多的優點,尤其是他的 api 非常豐富,但是在實際使用過程中,發現在導入幾千條數據的時候,有時容易發生異常,尤其是當老闆使用的時候,突然蹦出這麼一個異常,這個時候是沒辦法容忍的。

但是當改用成 easyexcel 的時候,不會出現這個問題,因此如果你經常要導入的數據量非常大,那麼我推薦你使用 easyexcel。

今天,我們就以 easyexcel 框架為例,結合實際開發案例,給大家詳細介紹一下 easyexcel 的使用,再下篇文章中,我們再來介紹 easypoi,可能也有理解不到位的地方,歡迎網友們批評指出!

二、程序實例

2.1、添加依賴包

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.2.6</version>
</dependency>

2.2、導出 excel

easyexcel 的導出支持兩種方式,一種是通過實體類註解方式來生成文件,另一種是通過動態參數化生成文件。

2.2.1、實體類註解方式生成文件

實體類註解方式生成文件,操作非常簡單,只需要在對應的屬性欄位上添加@ExcelProperty註解,然後填寫列名,配置就完成了,示例代碼如下:

public class UserEntity {

    @ExcelProperty(value = "姓名")
    private String name;

    @ExcelProperty(value = "年齡")
    private int age;

    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
    @ExcelProperty(value = "操作時間")
    private Date time;
 
 //set、get...
}
public static void main(String[] args) throws FileNotFoundException {
    List<UserEntity> dataList = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        UserEntity userEntity = new UserEntity();
        userEntity.setName("張三" + i);
        userEntity.setAge(20 + i);
        userEntity.setTime(new Date(System.currentTimeMillis() + i));
        dataList.add(userEntity);
    }
 //定義文件輸出位置
    FileOutputStream outputStream = new FileOutputStream(new File("/Users/panzhi/Documents/easyexcel-export-user1.xlsx"));
    EasyExcel.write(outputStream, UserEntity.class).sheet("用戶信息").doWrite(dataList);
}

運行程序,打開文件內容結果!

Java不固定列excel導入導出

2.2.2、動態參數化生成文件

動態參數化生成文件,這種方式小編使用的比較多,基於它,我們可以封裝一個公共的導出工具類,在後面會單獨介紹給大家,示例代碼如下:

public static void main(String[] args) throws FileNotFoundException {
    //定義表頭
    List<List<String>> headList = new ArrayList<>();
    headList.add(Lists.newArrayList("姓名"));
    headList.add(Lists.newArrayList("年齡"));
    headList.add(Lists.newArrayList("操作時間"));

    //定義數據體
    List<List<Object>> dataList = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        List<Object> data = new ArrayList<>();
        data.add("張三" + i);
        data.add(20 + i);
        data.add(new Date(System.currentTimeMillis() + i));
        dataList.add(data);
    }
    //定義文件輸出位置
    FileOutputStream outputStream = new FileOutputStream(new File("/Users/panzhi/Documents/easyexcel-export-user2.xlsx"));
    EasyExcel.write(outputStream).head(headList).sheet("用戶信息").doWrite(dataList);
}

運行程序,打開文件內容,結果與上面一致!

Java不固定列excel導入導出

2.2.3、複雜表頭的生成

很多時候我們需要導出的文件,表頭比較複雜,例如,我們想導出如下圖這樣一個複雜表頭,應該如何實現呢?

Java不固定列excel導入導出

如果你是使用在實體類上添加註解方式生成文件,那麼可以通過如下方式來實現:

public class UserEntity {

    @ExcelProperty(value = "班級")
    private String className;

    @ExcelProperty({"學生信息", "姓名"})
    private String name;

    @ExcelProperty({"學生信息", "年齡"})
    private int age;

    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
    @ExcelProperty({"學生信息", "入學時間"})
    private Date time;
 
 //set、get...
}

其中{“學生信息”, “姓名”}這種表達式,表示在當前列,插入多行數據,第一行插入的是學生信息名稱,第二行,插入的是姓名名稱,因此形成多級表頭!

如果你是使用的動態參數化生成文件,操作也同樣類似,示例代碼如下:

public static void main(String[] args) throws FileNotFoundException {
    //定義多級表頭
    List<List<String>> headList = new ArrayList<>();
    headList.add(Lists.newArrayList("班級"));
    headList.add(Lists.newArrayList("學生信息", "姓名"));
    headList.add(Lists.newArrayList("學生信息","年齡"));
    headList.add(Lists.newArrayList("學生信息","入學時間"));

    //定義數據體
    List<List<Object>> dataList = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        List<Object> data = new ArrayList<>();
        data.add("一年級~1班");
        data.add("張三" + i);
        data.add(20 + i);
        data.add(new Date(System.currentTimeMillis() + i));
        dataList.add(data);
    }
    //定義文件輸出位置
    FileOutputStream outputStream = new FileOutputStream(new File("/Users/panzhi/Documents/easyexcel-export-user3.xlsx"));
    EasyExcel.write(outputStream).head(headList).sheet("用戶信息").doWrite(dataList);
}

其中Lists.newArrayList(“學生信息”, “姓名”)表達的意思跟上面一樣,在當前列下插入多行,類似於:

List<String> list = new ArrayList<>();
list.add("學生信息");
list.add("姓名");

Lists.newArrayList編程來自於guava工具包!

2.2.4、自定義樣式

在實際使用過程中,我們可能還需要針對文件做一下樣式自定義,例如你想把表頭設置為紅色,內容設置為綠色,列寬、行寬都加大,應該如何實現呢?

Java不固定列excel導入導出

操作也很簡單,編寫一個自定義樣式類,然後在寫入的時候注入進去。

/**
 * 自定義樣式
 * @return
 */
private static HorizontalCellStyleStrategy customerStyle(){
    // 頭的策略
    WriteCellStyle headWriteCellStyle = new WriteCellStyle();
    // 背景設置為紅色
    headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
    WriteFont headWriteFont = new WriteFont();
    headWriteFont.setFontHeightInPoints((short)20);
    headWriteCellStyle.setWriteFont(headWriteFont);
    // 內容的策略
    WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
    // 這裡需要指定 FillPatternType 為FillPatternType.SOLID_FOREGROUND 不然無法顯示背景顏色.頭默認了 FillPatternType所以可以不指定
    contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
    // 背景綠色
    contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());
    WriteFont contentWriteFont = new WriteFont();
    // 字體大小
    contentWriteFont.setFontHeightInPoints((short)20);
    contentWriteCellStyle.setWriteFont(contentWriteFont);
    // 這個策略是 頭是頭的樣式 內容是內容的樣式 其他的策略可以自己實現
    HorizontalCellStyleStrategy horizontalCellStyleStrategy =
            new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    return horizontalCellStyleStrategy;
}

在寫入的時候,將其注入,例如下面的動態導出:

//通過registerWriteHandler方法,將自定義的樣式類注入進去
EasyExcel.write(outputStream).registerWriteHandler(customerStyle()).head(headList).sheet("用戶信息").doWrite(dataList);

2.3、導入 excel

easyexcel 的導入同樣也支持兩種方式,和上面一樣,一種是通過實體類註解方式來讀取文件,另一種是通過動態監聽器讀取文件。

2.3.1、實體類註解方式來讀取文件

實體類註解方式來讀取文件時,要讀取的 excel 表頭需要與實體類一一對應,以下面的 excel 文件為例!

Java不固定列excel導入導出

通過註解方式來讀取,既可以指定列的下表,也可以通過列名來映射,但是兩者只能取一個。

/**
 * 讀取實體類
 */
public class UserReadEntity {

    @ExcelProperty(value = "姓名")
    private String name;

    /**
     * 強制讀取第三個 這裡不建議 index 和 name 同時用,要麼一個對象只用index,要麼一個對象只用name去匹配
     */
    @ExcelProperty(index = 1)
    private int age;

    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
    @ExcelProperty(value = "操作時間")
    private Date time;

    //set、get...
}
public static void main(String[] args) throws FileNotFoundException {
 //同步讀取文件內容
    FileInputStream inputStream = new FileInputStream(new File("/Users/panzhi/Documents/easyexcel-user1.xls"));
    List<UserReadEntity> list = EasyExcel.read(inputStream).head(UserReadEntity.class).sheet().doReadSync();
    System.out.println(JSONArray.toJSONString(list));
}

運行程序,輸出結果如下:

[{"age":20,"name":"張三0","time":1616920360000},{"age":21,"name":"張三1","time":1616920360000},{"age":22,"name":"張三2","time":1616920360000},{"age":23,"name":"張三3","time":1616920360000},{"age":24,"name":"張三4","time":1616920360000},{"age":25,"name":"張三5","time":1616920360000},{"age":26,"name":"張三6","time":1616920360000},{"age":27,"name":"張三7","time":1616920360000},{"age":28,"name":"張三8","time":1616920360000},{"age":29,"name":"張三9","time":1616920360000}]

2.3.2、動態監聽器讀取文件

動態監聽器讀取文件,與上面的方式有一個明顯的區別是,我們需要重新寫一個實現類,來監聽 easyexcel 一行一行解析出來的數據,然後將數據封裝出來,基於此,我們可以編寫一套動態的導入工具類,詳細工具類會下面介紹到,示例代碼如下:

/**
 * 創建一個監聽器,繼承自AnalysisEventListener
 */
public class UserDataListener extends AnalysisEventListener<Map<Integer, String>> {

    private static final Logger LOGGER = LoggerFactory.getLogger(UserDataListener.class);

    /**
     * 表頭數據
     */
    private List<Map<Integer, String>> headList = new ArrayList<>();

    /**
     * 數據體
     */
    private List<Map<Integer, String>> dataList = new ArrayList<>();

    /**
     * 這裡會一行行的返回頭
     *
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        LOGGER.info("解析到一條頭數據:{}", JSON.toJSONString(headMap));
        headList.add(headMap);
    }

    /**
     * 這個每一條數據解析都會來調用
     *
     * @param data
     *            one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        LOGGER.info("解析到一條數據:{}", JSON.toJSONString(data));
        dataList.add(data);
    }

    /**
     * 所有數據解析完成了 都會來調用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        LOGGER.info("所有數據解析完成!");
    }

    public List<Map<Integer, String>> getHeadList() {
        return headList;
    }

    public List<Map<Integer, String>> getDataList() {
        return dataList;
    }
}
public static void main(String[] args) throws FileNotFoundException {
    FileInputStream inputStream = new FileInputStream(new File("/Users/panzhi/Documents/easyexcel-user1.xls"));
    //初始化一個監聽器
    UserDataListener userDataListener = new UserDataListener();
    //讀取文件數據
    EasyExcel.read(inputStream, userDataListener).sheet().doRead();
    System.out.println("表頭:" + JSONArray.toJSONString(userDataListener.getHeadList()));
    System.out.println("數據體:" + JSONArray.toJSONString(userDataListener.getDataList()));
}

運行程序,輸出結果如下:

表頭:[{0:"姓名",1:"年齡",2:"操作時間"}]
數據體:[{0:"張三0",1:"20",2:"2021-03-28 16:32:40"},{0:"張三1",1:"21",2:"2021-03-28 16:32:40"},{0:"張三2",1:"22",2:"2021-03-28 16:32:40"},{0:"張三3",1:"23",2:"2021-03-28 16:32:40"},{0:"張三4",1:"24",2:"2021-03-28 16:32:40"},{0:"張三5",1:"25",2:"2021-03-28 16:32:40"},{0:"張三6",1:"26",2:"2021-03-28 16:32:40"},{0:"張三7",1:"27",2:"2021-03-28 16:32:40"},{0:"張三8",1:"28",2:"2021-03-28 16:32:40"},{0:"張三9",1:"29",2:"2021-03-28 16:32:40"}]

其中key表示列下表!

2.3.3、複雜表頭讀取

在實際的開發中,我們還會遇到複雜表頭的數據讀取,以如下表頭為例,我們應該如何讀取呢?

Java不固定列excel導入導出

如果你是採用註解的方式導出的文件,同樣也可以通過註解方式來讀取,例如上文中,我們是使用如下實體類生成的文件,我們也可通過這個類讀取文件!

public class UserEntity {

    @ExcelProperty(value = "班級")
    private String className;

    @ExcelProperty({"學生信息", "姓名"})
    private String name;

    @ExcelProperty({"學生信息", "年齡"})
    private int age;

    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
    @ExcelProperty({"學生信息", "入學時間"})
    private Date time;
 
 //set、get
}
//讀取文件
List<UserEntity> list = EasyExcel.read(filePath).head(UserEntity.class).sheet().doReadSync();
System.out.println(JSONArray.toJSONString(list));

讀取結果如下:

[{"age":20,"className":"一年級~1班","name":"張三0","time":1618719961000},{"age":21,"className":"一年級~1班","name":"張三1","time":1618719961000},{"age":22,"className":"一年級~1班","name":"張三2","time":1618719961000},{"age":23,"className":"一年級~1班","name":"張三3","time":1618719961000},{"age":24,"className":"一年級~1班","name":"張三4","time":1618719961000},{"age":25,"className":"一年級~1班","name":"張三5","time":1618719961000},{"age":26,"className":"一年級~1班","name":"張三6","time":1618719961000},{"age":27,"className":"一年級~1班","name":"張三7","time":1618719961000},{"age":28,"className":"一年級~1班","name":"張三8","time":1618719961000},{"age":29,"className":"一年級~1班","name":"張三9","time":1618719961000}]

如果你是使用動態參數化來生成文件,那麼這個時候可以採用動態監聽器的方式來讀取文件,在讀取的時候需要指定數據所在行,示例代碼如下:

public static void main(String[] args) throws FileNotFoundException {
    FileInputStream inputStream = new FileInputStream(new File("/Users/panzhi/Documents/easyexcel-export-user4.xlsx"));
    //初始化一個監聽器
    UserDataListener userDataListener = new UserDataListener();
    //讀取文件數據,指定數據所在行使用headRowNumber方法
    EasyExcel.read(inputStream, userDataListener).sheet().headRowNumber(2).doRead();
    System.out.println("表頭:" + JSONArray.toJSONString(userDataListener.getHeadList()));
    System.out.println("數據體:" + JSONArray.toJSONString(userDataListener.getDataList()));
}

讀取結果如下:

表頭:[{0:"班級",1:"學生信息",2:"學生信息",3:"學生信息"},{0:"班級",1:"姓名",2:"年齡",3:"入學時間"}]
數據體:[{0:"一年級~1班",1:"張三0",2:"20",3:"2021-04-18 12:26:01"},{0:"一年級~1班",1:"張三1",2:"21",3:"2021-04-18 12:26:01"},{0:"一年級~1班",1:"張三2",2:"22",3:"2021-04-18 12:26:01"},{0:"一年級~1班",1:"張三3",2:"23",3:"2021-04-18 12:26:01"},{0:"一年級~1班",1:"張三4",2:"24",3:"2021-04-18 12:26:01"},{0:"一年級~1班",1:"張三5",2:"25",3:"2021-04-18 12:26:01"},{0:"一年級~1班",1:"張三6",2:"26",3:"2021-04-18 12:26:01"},{0:"一年級~1班",1:"張三7",2:"27",3:"2021-04-18 12:26:01"},{0:"一年級~1班",1:"張三8",2:"28",3:"2021-04-18 12:26:01"},{0:"一年級~1班",1:"張三9",2:"29",3:"2021-04-18 12:26:01"}]

三、動態導出導入工具類封裝

在實際使用開發中,我們不可能每來一個 excel 導入導出需求,就編寫一個方法,而且很多業務需求都是動態導入導出,沒辦法基於實體類註解的方式來讀取文件或者寫入文件

因此,基於動態參數化生成文件和動態監聽器讀取文件方法,我們可以單獨封裝一套動態導出導出工具類,省的我們每次都需要重新編寫大量重複工作,以下就是小編我在實際使用過程,封裝出來的工具類,在此分享給大家!

  • 動態導出工具類
public class DynamicEasyExcelExportUtils {

    private static final Logger log = LoggerFactory.getLogger(DynamicEasyExcelExportUtils.class);

    private static final String DEFAULT_SHEET_NAME = "sheet1";

    /**
     * 動態生成導出模版(單表頭)
     * @param headColumns 列名稱
     * @return            excel文件流
     */
    public static byte[] exportTemplateExcelFile(List<String> headColumns){
        List<List<String>> excelHead = Lists.newArrayList();
        headColumns.forEach(columnName -> { excelHead.add(Lists.newArrayList(columnName)); });
        byte[] stream = createExcelFile(excelHead, new ArrayList<>());
        return stream;
    }

    /**
     * 動態生成模版(複雜表頭)
     * @param excelHead   列名稱
     * @return
     */
    public static byte[] exportTemplateExcelFileCustomHead(List<List<String>> excelHead){
        byte[] stream = createExcelFile(excelHead, new ArrayList<>());
        return stream;
    }

    /**
     * 動態導出文件
     * @param headColumnMap  有序列頭部
     * @param dataList       數據體
     * @return
     */
    public static byte[] exportExcelFile(LinkedHashMap<String, String> headColumnMap, List<Map<String, Object>> dataList){
        //獲取列名稱
        List<List<String>> excelHead = new ArrayList<>();
        if(MapUtils.isNotEmpty(headColumnMap)){
            //key為匹配符,value為列名,如果多級列名用逗號隔開
            headColumnMap.entrySet().forEach(entry -> {
                excelHead.add(Lists.newArrayList(entry.getValue().split(",")));
            });
        }
        List<List<Object>> excelRows = new ArrayList<>();
        if(MapUtils.isNotEmpty(headColumnMap) && CollectionUtils.isNotEmpty(dataList)){
            for (Map<String, Object> dataMap : dataList) {
                List<Object> rows = new ArrayList<>();
                headColumnMap.entrySet().forEach(headColumnEntry -> {
                    if(dataMap.containsKey(headColumnEntry.getKey())){
                        Object data = dataMap.get(headColumnEntry.getKey());
                        rows.add(data);
                    }
                });
                excelRows.add(rows);
            }
        }
        byte[] stream = createExcelFile(excelHead, excelRows);
        return stream;
    }

    /**
     * 生成文件
     * @param excelHead
     * @param excelRows
     * @return
     */
    private static byte[] createExcelFile(List<List<String>> excelHead, List<List<Object>> excelRows){
        try {
            if(CollectionUtils.isNotEmpty(excelHead)){
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                EasyExcel.write(outputStream).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                        .head(excelHead)
                        .sheet(DEFAULT_SHEET_NAME)
                        .doWrite(excelRows);
                return outputStream.toByteArray();
            }
        } catch (Exception e) {
            log.error("動態生成excel文件失敗,headColumns:" + JSONArray.toJSONString(excelHead) + ",excelRows:" + JSONArray.toJSONString(excelRows), e);
        }
        return null;
    }

    /**
     * 導出文件測試
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        //導出包含數據內容的文件
        LinkedHashMap<String, String> headColumnMap = Maps.newLinkedHashMap();
        headColumnMap.put("className","班級");
        headColumnMap.put("name","學生信息,姓名");
        headColumnMap.put("sex","學生信息,性別");
        List<Map<String, Object>> dataList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            Map<String, Object> dataMap = Maps.newHashMap();
            dataMap.put("className", "一年級");
            dataMap.put("name", "張三" + i);
            dataMap.put("sex", "男");
            dataList.add(dataMap);
        }
        byte[] stream = exportExcelFile(headColumnMap, dataList);
        FileOutputStream outputStream = new FileOutputStream(new File("/Users/panzhi/Documents/easyexcel-export-user5.xlsx"));
        outputStream.write(stream);
        outputStream.close();
    }
}
  • 動態導入工具類
/**
 * 創建一個監聽器
 */
public class DynamicEasyExcelListener extends AnalysisEventListener<Map<Integer, String>> {

    private static final Logger LOGGER = LoggerFactory.getLogger(UserDataListener.class);

    /**
     * 表頭數據(存儲所有的表頭數據)
     */
    private List<Map<Integer, String>> headList = new ArrayList<>();

    /**
     * 數據體
     */
    private List<Map<Integer, String>> dataList = new ArrayList<>();

    /**
     * 這裡會一行行的返回頭
     *
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        LOGGER.info("解析到一條頭數據:{}", JSON.toJSONString(headMap));
        //存儲全部表頭數據
        headList.add(headMap);
    }

    /**
     * 這個每一條數據解析都會來調用
     *
     * @param data
     *            one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        LOGGER.info("解析到一條數據:{}", JSON.toJSONString(data));
        dataList.add(data);
    }

    /**
     * 所有數據解析完成了 都會來調用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 這裡也要保存數據,確保最後遺留的數據也存儲到資料庫
        LOGGER.info("所有數據解析完成!");
    }

    public List<Map<Integer, String>> getHeadList() {
        return headList;
    }

    public List<Map<Integer, String>> getDataList() {
        return dataList;
    }
}
/**
 * 編寫導入工具類
 */
public class DynamicEasyExcelImportUtils {

    /**
     * 動態獲取全部列和數據體,默認從第一行開始解析數據
     * @param stream
     * @return
     */
    public static List<Map<String,String>> parseExcelToView(byte[] stream) {
        return parseExcelToView(stream, 1);
    }

    /**
     * 動態獲取全部列和數據體
     * @param stream           excel文件流
     * @param parseRowNumber   指定讀取行
     * @return
     */
    public static List<Map<String,String>> parseExcelToView(byte[] stream, Integer parseRowNumber) {
        DynamicEasyExcelListener readListener = new DynamicEasyExcelListener();
        EasyExcelFactory.read(new ByteArrayInputStream(stream)).registerReadListener(readListener).headRowNumber(parseRowNumber).sheet(0).doRead();
        List<Map<Integer, String>> headList = readListener.getHeadList();
        if(CollectionUtils.isEmpty(headList)){
            throw new RuntimeException("Excel未包含表頭");
        }
        List<Map<Integer, String>> dataList = readListener.getDataList();
        if(CollectionUtils.isEmpty(dataList)){
            throw new RuntimeException("Excel未包含數據");
        }
        //獲取頭部,取最後一次解析的列頭數據
        Map<Integer, String> excelHeadIdxNameMap = headList.get(headList.size() -1);
        //封裝數據體
        List<Map<String,String>> excelDataList = Lists.newArrayList();
        for (Map<Integer, String> dataRow : dataList) {
            Map<String,String> rowData = new LinkedHashMap<>();
            excelHeadIdxNameMap.entrySet().forEach(columnHead -> {
                rowData.put(columnHead.getValue(), dataRow.get(columnHead.getKey()));

            });
            excelDataList.add(rowData);
        }
        return excelDataList;
    }

    /**
     * 文件導入測試
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        FileInputStream inputStream = new FileInputStream(new File("/Users/panzhi/Documents/easyexcel-export-user5.xlsx"));
        byte[] stream = IoUtils.toByteArray(inputStream);
        List<Map<String,String>> dataList = parseExcelToView(stream, 2);
        System.out.println(JSONArray.toJSONString(dataList));
        inputStream.close();
    }

}

為了方便後續的操作流程,在解析數據的時候,會將列名作為key!

四、總結

本文主要以實際使用場景為例,對 easyexcel 的使用做了簡單的介紹,尤其是動態導出導出,基於業務的需要,做了一個公共的工具類,方便後續進行快速開發,避免重複的勞動!

當然,easyexcel 的功能還不只上面介紹的那些內容,還有基於模版進行excel的填充,web 端restful的導出導出,使用方法大致都差不多,具體可以參與官方的文檔,地址如下:https://www.yuque.com/easyexcel/doc/read#1bfaf593

最後,希望本文對大家有所幫助!

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/202508.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
投稿專員的頭像投稿專員
上一篇 2024-12-06 14:12
下一篇 2024-12-06 14:12

相關推薦

發表回復

登錄後才能評論