JAVA使用hutool poi工具讀取Excel表格指定行列范圍的數據


1.pom.xml依賴配置

        <!-- huTool工具箱 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.22</version>
        </dependency>

        <!-- poi -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.1.0</version>
        </dependency>

 

2.代碼

單元格數據模型對象

package com.hdwang.exceltest;

import cn.hutool.json.JSONUtil;

/**
 * 單元格數據
 */
public class CellData {

    /**
     * 行號
     */
    private int rowIndex;

    /**
     * 列號
     */
    private int cellIndex;

    /**
     * 單元格數值
     */
    private Object value;

    public int getRowIndex() {
        return rowIndex;
    }

    public void setRowIndex(int rowIndex) {
        this.rowIndex = rowIndex;
    }

    public int getCellIndex() {
        return cellIndex;
    }

    public void setCellIndex(int cellIndex) {
        this.cellIndex = cellIndex;
    }

    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return JSONUtil.toJsonStr(this);
    }
}

 

Bean對象屬性賦值注解

package com.hdwang.exceltest;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 列號,用於給bean對象的屬性賦指定列的值
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.FIELD})
public @interface ColIndex {

    /**
     * 列索引號(從0開始),與name二者填一個即可,優先級高於name
     *
     * @return
     */
    int index() default -1;

    /**
     * 列名稱(從A開始),與index二者填一個即可,優先級低於index
     *
     * @return
     */
    String name() default "";
}

 

表格數據對象

package com.hdwang.exceltest;

import cn.hutool.json.JSONUtil;

/**
 * 證券月報
 */
public class ZhenquanReport {

    /**
     * 名稱
     */
    @ColIndex(name = "B")
    private String name;

    /**
     * 數值
     */
    @ColIndex(index = 2)
    private String value;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return JSONUtil.toJsonStr(this);
    }
}

 

讀取方法代碼

package com.hdwang.exceltest;

import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.cell.CellHandler;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.*;

import java.io.File;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

public class Main {
    public static void main(String[] args) {
        try {
            File templateFile = new File("C:\\Users\\hdwang\\Desktop\\test.xlsx");
            List<List<CellData>> rowDataList = readExcelData(templateFile, 2, Integer.MAX_VALUE, 1, Integer.MAX_VALUE);
            System.out.println(rowDataList);

            List<ZhenquanReport> reports = convertExcelDataToBeanList(rowDataList, ZhenquanReport.class);
            System.out.println(reports);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
/**
     * 讀取表格數據
     *
     * @param templateFile   文件
     * @param startRowIndex  起始行號(從0開始)
     * @param endRowIndex    結束行號(從0開始)
     * @param startCellIndex 起始列號(從0開始)
     * @param endCellIndex   結束列號(從0開始)
     * @return 表格數據
     */
    private static List<List<CellData>> readExcelData(File templateFile, int startRowIndex, int endRowIndex, int startCellIndex, int endCellIndex) {
        ExcelReader excelReader = ExcelUtil.getReader(templateFile, 0);
        List<List<CellData>> rowDataList = new ArrayList<>();
        AtomicInteger rowIndex = new AtomicInteger(-1);
        excelReader.read(startRowIndex, endRowIndex, new CellHandler() {
            @Override
            public void handle(Cell cell, Object value) {
                if (cell == null) {
                    //無單元格跳過
                    return;
                }
                if (cell.getColumnIndex() < startCellIndex || cell.getColumnIndex() > endCellIndex) {
                    //列號不在范圍內跳過
                    return;
                }

                //新行的數據
                if (cell.getRowIndex() != rowIndex.get()) {
                    rowDataList.add(new ArrayList<>());
                }
                rowIndex.set(cell.getRowIndex());
                //取出新行數據對象存儲單元格數據
                List<CellData> cellDataList = rowDataList.get(rowDataList.size() - 1);
                CellData cellData = new CellData();
                cellData.setRowIndex(cell.getRowIndex());
                cellData.setCellIndex(cell.getColumnIndex());
                cellData.setValue(value);
                cellDataList.add(cellData);
            }
        });
        return rowDataList;
    }

    /**
     * 轉換表格數據為bean對象列表
     *
     * @param rowDataList 表格數據
     * @param tClass      bean類型
     * @param <T>
     * @return bean對象列表
     */
    private static <T> List<T> convertExcelDataToBeanList(List<List<CellData>> rowDataList, Class<T> tClass) {
        if (CollectionUtils.isEmpty(rowDataList)) {
            return new ArrayList<>();
        }
        List<T> beanList = new ArrayList<>();
        for (List<CellData> rowData : rowDataList) {
            try {
                //實例化bean對象
                T bean = tClass.newInstance();
                //遍歷字段並賦值
                Field[] fields = tClass.getDeclaredFields();
                for (Field field : fields) {
                    if (field.isAnnotationPresent(ColIndex.class)) {
                        ColIndex colIndex = field.getAnnotation(ColIndex.class);
                        int index = colIndex.index();
                        String name = colIndex.name();
                        if (index != -1) {
                            //do nothing
                        } else if (!"".equals(name)) {
                            //列名轉索引號(補0為了適應下述方法)
                            index = ExcelUtil.colNameToIndex(name + "0");
                        } else {
                            throw new RuntimeException("請設置列號(ColIndex注解值必須配置一個)");
                        }
                        //從行數據中找到指定單元格數據給字段賦值
                        final int i = index;
                        CellData cellData = rowData.stream().filter(x -> x.getCellIndex() == i).findFirst().orElse(null);
                        if (cellData != null) {
                            Object value = cellData.getValue();
                            if (field.getType().getName().equals(String.class.getName())) {
                                value = String.valueOf(value);
                            }
                            field.setAccessible(true);
                            field.set(bean, value);
                        }
                    }
                }
                beanList.add(bean);
            } catch (Exception ex) {
                throw new RuntimeException("實例化對象失敗", ex);
            }
        }
        return beanList;
    }
}

 

 

3.表格

 

 

4.輸出結果

表格數據對象

[
    [
        {
            "cellIndex": 1,
            "rowIndex": 2,
            "value": "凈資產"
        },
        {
            "cellIndex": 2,
            "rowIndex": 2,
            "value": 10000
        },
        {
            "cellIndex": 3,
            "rowIndex": 2,
            "value": " "
        },
        {
            "cellIndex": 4,
            "rowIndex": 2,
            "value": 1
        }
    ],
    [
        {
            "cellIndex": 1,
            "rowIndex": 3,
            "value": "市值"
        },
        {
            "cellIndex": 2,
            "rowIndex": 3,
            "value": 20000
        },
        {
            "cellIndex": 4,
            "rowIndex": 3,
            "value": 2
        }
    ],
    [
        {
            "cellIndex": 1,
            "rowIndex": 4,
            "value": "標題"
        }
    ],
    [
        {
            "cellIndex": 1,
            "rowIndex": 5,
            "value": "凈利潤"
        },
        {
            "cellIndex": 2,
            "rowIndex": 5,
            "value": 1000
        },
        {
            "cellIndex": 4,
            "rowIndex": 5,
            "value": 3
        }
    ]
]

 轉成bean對象列表

[{"name":"凈資產","value":"10000"}, {"name":"市值","value":"20000"}, {"name":"標題"}, {"name":"凈利潤","value":"1000"}]

 

5.原理總結

hutool poi 工具對POI進行了包裝,實現了很多功能函數。可是在項目實踐中發現還是有所不足。現在自己編寫自定義取行列范圍的數據並實現模型轉換功能,從而方便對表格實現數據讀取與單元格定位操作等。相關實現技術原理如下:

(1) 基於 public void read(int startRowIndex, int endRowIndex, CellHandler cellHandler)  函數實現行過濾,在CellHandler內部實現列過濾,這樣便實現了行列過濾,且取出了行列信息,便於對單元格定位等。

(2) 將CellData轉換為Bean對象的時候,采用反射技術讀取bean對象字段的注解配置的列號信息,從而找到指定的CellData取值並賦值到字段上去。

 

6.附錄

最新源碼文件:https://github.com/hdwang123/exceltest

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM