java 读取excel(支持xlsx、xls格式, 支持合并单元格)

推荐:

更加规范和完整的工具:

码云-chimm.excel

码云-chimm.excel:设置单元格公式 值不对Issuse

个人学习练手的工具:java创建excel(不用设置样式,支持xlsx、xls格式, 不支持合并单元格)

java读excel

实现效果

概念

依赖

代码实现

测试代码

ExcelReader.java 工具类

实现效果

将excel看成一个二维表,将数据存放在List<List>>中。[0,0]表示第一个单元格,[5,3]表示第6行,第4列数据,若空行或空列也会存在对应的下标位置。

合并单元的值取最左上角单元格的值。每个子单元格的值与合并单元格的值保持一致。如:[0行,1行,0列,1列]为合并单元格,值为“AAA”。那么[0,0]、[0,1]、[1,0]、[1,1]的值都为“AAA”。

可将某行为表头,将excel内容封装为bean或map集合,见sheetList2Bean、sheetList2Map方法。

概念

excel文件对应的是 workbook(xls xlsx)

每个workbook 中有多个 sheet

每个sheet有多行 Row

每行有多列 Cell

sheet.getLastRowNum:获取sheet最后有数据行的下标(包含空行)。最后有数据的行是第n行则返回n-1,一行数据都没有则返回-1。行遍历,下标从0开始

row.getLastCellNum:获取某行最后有数据的列(包含空列)。只有第一列有数据则返回1,最后有数据的列是第n列则返回n,一列数据都没有则返回-1。列遍历,下标从0开始

sheet.getPhysicalNumberOfRows:获取sheet中实际有数据的行数(即,非默认格式的行数),一行数据都没有则返回0

row.getPhysicalNumberOfCells:获取某行实际有数据的列数(即,非默认格式的列数),一列数据都没有则返回0

注意事项

1、获取的excel行数不正确解决方法

2、poi认为的有数据:一般情况,非默认格式的行或列都是有数据的。特例,行高改变,被认为该行是有数据的;列宽改变,被认为该列是无数据列。

3、java进行Excel导入数字类型的处理:https://www.cnblogs.com/renjiaqi/p/10072861.html、https://www.cnblogs.com/renjiaqi/p/10072861.html

上面的执行的结果是:

case NUMERIC:

cellValue = String.valueOf(cell.getNumericCellValue());

break;

1.242532523632E12 //不是我们想要的字符串呢

那就使用poi的另一个神器NumberToTextConverter,改写switch的代码:

case NUMERIC:

// 改成这样

cellValue = NumberToTextConverter.toText(cell.getNumericCellValue());

break;

执行后返回:

1242532523632 //我们想要的结果

1

2

3

4

5

6

7

8

9

10

11

12

13

//引用poi包工具类数字转化工具

import org.apache.poi.ss.util.NumberToTextConverter;

//引用poi包时间格式判断工具

import org.apache.poi.hssf.usermodel.HSSFDateUtil;

//判断单元格的数据类型为数值,且不为时间的

if(!(cell.getCellType()!= Cell.CELL_TYPE_NUMERIC ||

  HSSFDateUtil.isCellDateFormatted(cell))) {

  String val=NumberToTextConverter.toText(cell.getNumericCellValue());

  System.out.println("---val:"+val);

}

1

2

3

4

5

6

7

8

9

10

11

依赖

<dependency>

    <groupId>org.apache.poi</groupId>

    <artifactId>poi</artifactId>

    <version>4.1.2</version>

</dependency>

<dependency>

    <groupId>org.apache.poi</groupId>

    <artifactId>poi-ooxml</artifactId>

    <version>4.1.2</version>

</dependency>

1

2

3

4

5

6

7

8

9

10

代码实现

所有代码都在一个类,方便直接使用。

完整代码及excel模板:https://gitee.com/andus_top/java-excel

测试代码

public static void main(String[] args) throws IOException, IllegalAccessException {

        ExcelReader excelReader = new ExcelReader("C:\\Users\\YSL\\Desktop\\read-test.xlsx");

        // test1: 获取sheet所有或指定位置的内容

        System.out.println("test1: 获取sheet所有或指定位置的内容");

        //List<List<Object>> sheetContent = excelReader.getSheetContent(0, 5, 11, 1, 2);

        List<List<Object>> sheetContent = excelReader.getSheetContent(0);

        for (List<Object> objects : sheetContent) {

            if(objects != null) {

                for (Object object : objects) {

                    if (object != null) {

                        System.out.print(String.valueOf(object) + ", ");

                    }else{

                        System.out.print("null, ");

                    }

                }

                System.out.println("\n");

            }else{

                System.out.println("跳过空行");

            }

        }

        // test2: 遍历excel每个sheet,获取sheet指定范围的内容

        System.out.println("\ntest2: 遍历excel每个sheet,获取sheet指定范围的内容");

        excelReader.clearCache();

        Map<String, List<List<Object>>> workbookContentMap = excelReader.getWorkbookContentMap(5, 11, 1, 2);

        workbookContentMap.forEach((k, v) -> {

            System.out.println(k);

            v.forEach(i -> {

                if(i != null)

                    i.forEach(j -> {

                        System.out.print(j + ", ");

                    });

                System.out.println();

            });

        });

        // test3: 遍历excel每个sheet,获取sheet指定范围的内容

        System.out.println("\ntest3: 遍历excel每个sheet,获取sheet指定范围的内容");

        excelReader.clearCache();

        List<List<List<Object>>> workbookContentList = excelReader.getWorkbookContentList();

        //List<List<List<Object>>> workbookContentList = excelReader.getWorkbookContentList(5, 11, 1, 2);

        workbookContentList.forEach(sheet -> {

            sheet.forEach(row -> {

                if(row != null) {

                    row.forEach(cell -> {

                        if (cell != null)

                            System.out.print(cell + ", ");

                    });

                    System.out.println();

                }

            });

        });

        // test4: 获取sheet内容,按指定行作为表头,转存为List<Bean> 结构

        System.out.println("\ntest4: 获取sheet内容,按指定行作为表头,转存为List<Bean> 结构");

        List<Bean> beans = excelReader.sheetList2Bean(0, 1, () -> new Bean());

        //List<Bean> beans = excelReader.sheetList2Bean("Sheet1", 1, Bean::new);

        beans.forEach(System.out::println);

        // test5: 获取sheet内容,按指定行作为表头,转存为 Map 结构

        System.out.printf("\ntest5: 获取sheet内容,按指定行作为表头,转存为 Map 结构");

        List<Map<String, Object>> mapList = excelReader.sheetList2Map("Sheet1", 1);

        mapList.forEach(System.out::println);

        excelReader.close();

    }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

ExcelReader.java 工具类

import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import org.apache.poi.ss.usermodel.*;

import org.apache.poi.ss.util.CellRangeAddress;

import org.apache.poi.xssf.usermodel.XSSFWorkbook;

//引用poi包工具类数字转化工具

import org.apache.poi.ss.util.NumberToTextConverter;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.lang.reflect.Field;

import java.lang.reflect.Modifier;

import java.time.LocalDateTime;

import java.time.format.DateTimeFormatter;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.function.Supplier;

/**

* 读excel

* @author andus.top

* @date 2021/6/1  20:41

*/

public class ExcelReader {

    private Workbook workbook;

    private Map<String, List<List<Object>>> workbookContent;

    private FileInputStream in;

    public ExcelReader(File file) throws IOException {

        String fileName = file.getName();

        in = new FileInputStream(file);

        try{

            if(fileName.endsWith(".xls")){

                workbook = new HSSFWorkbook(in);

            }else if(fileName.endsWith(".xlsx")){

                workbook = new XSSFWorkbook(in);

            }

        }finally {

        }

        if(workbook == null){

            throw new RuntimeException("excel 文件格式错误");

        }

    }

    public ExcelReader(String filePath) throws IOException {

        this(new File(filePath));

    }

    public ExcelReader(FileInputStream in, boolean xls) throws IOException {

        this.in = in;

        if(xls){

            workbook = new HSSFWorkbook(this.in);

        }else{

            workbook = new XSSFWorkbook(this.in);

        }

    }

    /**

    * 获取sheet内容,按指定行作为表头,转存为List&lt;T&gt; 结构

    * @param sheetIndex sheet下标,从0开始

    * @param keyIndex 第几行用作key,从0开始。注意,key行的长度小于内容行,多余的内容会丢失;反之会放入null

    * @param keyIndex sup

    * @author andus.top

    * @date 2021/6/1 19:17

    * @return 将sheet内容从list,转为按指定行做key的map

    */

    public <T> List<T>  sheetList2Bean(int sheetIndex, int keyIndex, Supplier<T> sup) throws IllegalAccessException {

        return sheetList2Bean(getSheetContent(sheetIndex), keyIndex, sup);

    }

    /**

    * 获取sheet内容,按指定行作为表头,转存为List&lt;T&gt; 结构

    * @param sheetName sheet名称

    * @param keyIndex 第几行用作key,从0开始。注意,key行的长度小于内容行,多余的内容会丢失;反之会放入null

    * @param keyIndex sup

    * @author andus.top

    * @date 2021/6/1 19:17

    * @return 将sheet内容从list,转为按指定行做key的map

    */

    public <T> List<T>  sheetList2Bean(String sheetName, int keyIndex, Supplier<T> sup) throws IllegalAccessException {

        return sheetList2Bean(getSheetContent(sheetName), keyIndex, sup);

    }

    /**

    * 获取sheet内容,按指定行作为表头,转存为map结构

    * @param sheetIndex sheet下标,从0开始

    * @param keyIndex 第几行用作key,从0开始。注意,key行的长度小于内容行,多余的内容会丢失;反之会放入null

    * @author andus.top

    * @date 2021/6/1 19:17

    * @return 将sheet内容从list,转为按指定行做key的map

    */

    public List<Map<String, Object>> sheetList2Map(int sheetIndex, int keyIndex){

        return sheetList2Map(getSheetContent(sheetIndex), keyIndex);

    }

    /**

    * 获取sheet内容,按指定行作为表头,转存为map结构

    * @param sheetName sheet名称

    * @param keyIndex 第几行用作key,从0开始。注意,key行的长度小于内容行,多余的内容会丢失;反之会放入null

    * @author andus.top

    * @date 2021/6/1 19:17

    * @return 将sheet内容从list,转为按指定行做key的map

    */

    public List<Map<String, Object>> sheetList2Map(String sheetName, int keyIndex){

        return sheetList2Map(getSheetContent(sheetName), keyIndex);

    }

    /**

    * 获取sheet所有或指定位置的内容。若为合并单元格,子单元格会的值为合并单元格的值<br>

    * note:若在该方法之前已读取了excel数据,那么需调用clearCache方法,清空之前的数据,否则指定范围读取无效

    * @param sheetIndex sheet下标,从0开始

    * @param range  下标从0开始。<b>要么不传,要么4个值都传。</b>-1表示取到最后一行或最后一列<br>

    *  &nbsp; range结构为:[int startRow, int endRow, int startCol, int endCol] <br>

    *  &emsp;&emsp;  startRow 开始的行,从0开始<br>

    *  &emsp;&emsp;  endRow 结束的行<br>

    *  &emsp;&emsp;  startCol 开始的列,从0开始<br>

    *  &emsp;&emsp;  endCol 结束的列<br>

    * @author andus.top

    * @date 2021/6/1 20:46

    */

    public List<List<Object>> getSheetContent(int sheetIndex, Integer...range){

        return getWorkbookContentList(range).get(sheetIndex);

    }

    /**

    * 获取sheet所有或指定位置的内容。若为合并单元格,子单元格会的值为合并单元格的值<br>

    * note:若在该方法之前已读取了excel数据,那么需调用clearCache方法,清空之前的数据,否则指定范围读取无效

    * @param sheetName sheet名称

    * @param range  下标从0开始。<b>要么不传,要么4个值都传。</b>-1表示取到最后一行或最后一列<br>

    *  &nbsp; range结构为:[int startRow, int endRow, int startCol, int endCol] <br>

    *  &emsp;&emsp;  startRow 开始的行,从0开始<br>

    *  &emsp;&emsp;  endRow 结束的行<br>

    *  &emsp;&emsp;  startCol 开始的列,从0开始<br>

    *  &emsp;&emsp;  endCol 结束的列<br>

    * @author andus.top

    * @date 2021/6/1 20:46

    */

    public List<List<Object>> getSheetContent(String sheetName, Integer...range){

        return getWorkbookContentMap(range).get(sheetName);

    }

    /**

    * 遍历excel,获取sheet所有或指定范围的内容。返回List集合<br>

    * note:若在该方法之前已读取了excel数据,那么需调用clearCache方法,清空之前的数据,否则指定范围读取无效

    * @param range  下标从0开始。<b>要么不传,要么4个值都传。</b>-1表示取到最后一行或最后一列<br>

    *  &nbsp; range结构为:[int startRow, int endRow, int startCol, int endCol] <br>

    *  &emsp;&emsp;  startRow 开始的行,从0开始<br>

    *  &emsp;&emsp;  endRow 结束的行<br>

    *  &emsp;&emsp;  startCol 开始的列,从0开始<br>

    *  &emsp;&emsp;  endCol 结束的列<br>

    * @author andus.top

    * @date 2021/6/1 20:41

    * @return 按照sheetIndex->row->cell 逐层获取。List&lt;List&lt;Object&gt;&gt; 为每个sheet数据;List&lt;Object&gt; 为每行数据

    */

    public List<List<List<Object>>> getWorkbookContentList(Integer...range){

        if(workbookContent == null || workbookContent.isEmpty()){

            getWorkbookContentMap(range);

        }

        List<List<List<Object>>> rlist = new ArrayList<>(workbookContent.size());

        workbookContent.forEach((k,v) -> rlist.add(v));

        return rlist;

    }

    /**

    * 遍历excel,获取sheet所有或指定范围的内容。返回Map集合<br>

    * note:若在该方法之前已读取了excel数据,那么需调用clearCache方法,清空之前的数据,否则指定范围读取无效

    * @param range  下标从0开始。<b>要么不传,要么4个值都传。</b>-1表示取到最后一行或最后一列<br>

    *  &nbsp; range结构为:[int startRow, int endRow, int startCol, int endCol] <br>

    *  &emsp;&emsp;  startRow 开始的行,从0开始<br>

    *  &emsp;&emsp;  endRow 结束的行<br>

    *  &emsp;&emsp;  startCol 开始的列,从0开始<br>

    *  &emsp;&emsp;  endCol 结束的列<br>

    * @author andus.top

    * @date 2021/6/1 20:41

    * @return 按照sheetName->row->cell 逐层获取。key为sheet名称;vlaue为每个sheet数据;List&lt;Object&gt; 为每行数据

    */

    public Map<String, List<List<Object>>> getWorkbookContentMap(Integer...range){

        if(range == null || range.length%4 != 0){

            System.err.println("sheet range format is error");

            return null;

        }

        if(workbookContent == null || workbookContent.isEmpty()){

            workbookContent = new HashMap<>();

            int numberOfSheets = workbook.getNumberOfSheets();

            for (int x = 0; x < numberOfSheets; x++) {

                Sheet sheet = workbook.getSheetAt(x);

                workbookContent.put(sheet.getSheetName(), getSheetContent(sheet, range));

            }

        }

        return workbookContent;

    }

    /**

    * 清空workbookContent。<br>

    * 需要指定范围读取数据时,需清空之前的数据

    * @author andus.top

    * @date 2021/6/29 14:24

    */

    public void clearCache(){

        if(workbookContent != null)workbookContent.clear();

    }

    /**

    * 关闭流

    * @author andus.top

    * @date 2021/6/2 20:26

    */

    public void close(){

        try {

            if(workbook != null){

                workbook.close();

            }

            if(in != null){

                in.close();

            }

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

    /**

    * 获取每个sheet的数据。合并单元格,获取第一个cell的值

    * @param sheet 当前org.apache.poi.ss.usermodel.Sheet对象

    * @param range  下标从0开始。<b>要么不传,要么4个值都传。</b>-1表示取到最后一行或最后一列<br>

    *  &nbsp; range结构为:[int startRow, int endRow, int startCol, int endCol] <br>

    *  &emsp;&emsp;  startRow 开始的行,从0开始<br>

    *  &emsp;&emsp;  endRow 结束的行<br>

    *  &emsp;&emsp;  startCol 开始的列,从0开始<br>

    *  &emsp;&emsp;  endCol 结束的列<br>

    * @author andus.top

    * @date 2021/6/1 20:50

    */

    private List<List<Object>> getSheetContent(Sheet sheet, Integer...range){

        if(sheet == null){

            System.err.println("sheet is null");

            return null;

        }

        // // fixme 【已修复】开始行设置为0,保证通过下标获取数据时,不会出错。

        Integer startRow = 0; // sheet.getFirstRowNum():第0行无数据,第1行有数据,此时返回1

        Integer endRow = sheet.getLastRowNum(); // n行返回n-1

        if(range != null && range.length == 4){

            // 开始行和结束行小于0,或者结束行小于开始行 ,或者其他参数错误时,使用getFirstRowNum或

            if(range[0] > 0 && range[0] <= endRow && (range[0] <= range[1] || range[1] < 0)){ // range[1] < 0 与 getLastRowNum 等价

                startRow = range[0];

            }

            if(range[1] > 0 && range[1] <= endRow  && range[0] <= range[1]){

                endRow = range[1];

            }

        }

        List<List<Object>> slist = new ArrayList<>((endRow - startRow) + 1);

        // 遍历指定范围的行

        for (int x = startRow; x <= endRow; x++){

            slist.add(getRow(sheet.getRow(x), range));

        }

        return slist;

    }

    /**

    * 获取当前row的数据。合并单元格,获取第一个cell的值

    * @param row 当前org.apache.poi.ss.usermodel.Row对象

    * @param range  下标从0开始。<b>要么不传,要么4个值都传。</b>-1表示取到最后一行或最后一列<br>

    *  &nbsp; range结构为:[int startRow, int endRow, int startCol, int endCol] <br>

    *  &emsp;&emsp;  startRow 开始的行,从0开始<br>

    *  &emsp;&emsp;  endRow 结束的行<br>

    *  &emsp;&emsp;  startCol 开始的列,从0开始<br>

    *  &emsp;&emsp;  endCol 结束的列<br>

    * @author andus.top

    * @date 2021/6/1 20:51

    */

    private List<Object> getRow(Row row, Integer...range){

        if(row == null){

            return null;

        }

        // fixme  【已修复】开始行设置为0,保证每列数据不会错误。即,保证转换为key,value是 不会错位

        short startCol = 0; // row.getFirstCellNum():第0列无数据,第1列有数据,此时返回1

        short endCol = (short)(row.getLastCellNum()-(short) 1); //  n列,返回n。fixme: 【已修复】所以最大列数需减一

        if(range != null && range.length == 4){

            // 开始行和结束行小于0,或者结束行小于开始行 ,或者其他参数错误时,使用getFirstRowNum或

            if(range[2] > 0 && range[2] <= endCol && (range[2] <= range[3] || range[3] < 0)){ // range[3] < 0 与 getLastCellNum 等价

                startCol = Short.valueOf(String.valueOf(range[2]));

            }

            if(range[3] > 0 && range[3] <= endCol  && range[2] <= range[3]){

                endCol = Short.valueOf(String.valueOf(range[3]));

            }

        }

        List<Object> rlist = new ArrayList<>();

        // 遍历指定范围的列

        for (int x = startCol; x <= endCol; x++) {

            Cell cell = row.getCell(x);

            if(cell != null) {

                boolean isMerge = isMergedRegion(row.getSheet(), row.getRowNum(), cell.getColumnIndex());

                //判断是否具有合并单元格

                if (isMerge) {

                    rlist.add(getMergedRegionValue(row.getSheet(), row.getRowNum(), cell.getColumnIndex()));

                } else {

                    rlist.add(getCellValue(cell));

                }

            }else{

                // 添加null

                rlist.add(getCellValue(cell));

            }

        }

        // 直接迭代,读取所有行

        // List<Object> rlist = new ArrayList<>();

        // row.cellIterator().forEachRemaining(cell -> rlist.add(getCell(cell)));

        return rlist;

    }

    /**

    * 获取当前cell的数据

    * @param cell 当前org.apache.poi.ss.usermodel.Cell对象

    * @author andus.top

    * @date 2021/6/1 20:52

    */

    private Object getCellValue(Cell cell){

        if(cell == null){

            return null;

        }else{

            CellType cft = cell.getCellType();

            switch (cft){

                case BLANK:

                    return "";

                case BOOLEAN:

                    return cell.getBooleanCellValue();

                case ERROR:

                    return cell.getErrorCellValue();

                case NUMERIC:

                    if(DateUtil.isCellDateFormatted(cell)){

                      return cell.getLocalDateTimeCellValue();

                    }else{//判断单元格的数据类型为数值,且不为时间的

                        return NumberToTextConverter.toText(cell.getNumericCellValue());

                    }

                case FORMULA:

                    return cell.getCellFormula();

                    //return cell.getStringCellValue();

                default:

                    return cell.getStringCellValue();

                    //return cell.getRichStringCellValue().toString();

            }

        }

    }

    /**

    * 判断指定的单元格是否是合并单元格

    * @param sheet

    * @param row 行下标

    * @param column 列下标

    * @return true:是合并单元格,false:非合并单元格

    */

    private static boolean isMergedRegion(Sheet sheet, int row ,int column) {

        // 得到一个sheet中有多少个合并单元格

        int sheetMergeCount = sheet.getNumMergedRegions();

        for (int i = 0; i < sheetMergeCount; i++) {

            // 得出具体的合并单元格

            CellRangeAddress range = sheet.getMergedRegion(i);

            // 得到合并单元格的起始行, 结束行, 起始列, 结束列

            int firstColumn = range.getFirstColumn();

            int lastColumn = range.getLastColumn();

            int firstRow = range.getFirstRow();

            int lastRow = range.getLastRow();

            // 判断该单元格是否在合并单元格范围之内, 如果是, 则返回 true

            if(row >= firstRow && row <= lastRow){

                if(column >= firstColumn && column <= lastColumn){

                    return true;

                }

            }

        }

        return false;

    }

    /**

    * 获取合并单元格的值<br>

    * 即获取合并单元格第一个cell的值

    * @param sheet 当前sheet

    * @param row 当前行下标

    * @param column 当前列下标

    * @return 该合并单元格的值

    */

    private Object getMergedRegionValue(Sheet sheet ,int row , int column){

        // 获得一个 sheet 中合并单元格的数量

        int sheetMergeCount = sheet.getNumMergedRegions();

        // 遍历合并单元格

        for(int i = 0 ; i < sheetMergeCount ; i++){

            // 得出具体的合并单元格

            CellRangeAddress ca = sheet.getMergedRegion(i);

            // 得到合并单元格的起始行, 结束行, 起始列, 结束列

            int firstColumn = ca.getFirstColumn();

            int lastColumn = ca.getLastColumn();

            int firstRow = ca.getFirstRow();

            int lastRow = ca.getLastRow();

            // 获取合并单元格第一个cell的值

            if(row >= firstRow && row <= lastRow){

                if(column >= firstColumn && column <= lastColumn){

                    Row fRow = sheet.getRow(firstRow);

                    Cell fCell = fRow.getCell(firstColumn);

                    return getCellValue(fCell) ;

                }

            }

        }

        return null ;

    }

    private <T> List<T>  sheetList2Bean(List<List<Object>> sheet , int keyIndex, Supplier<T> sup) throws IllegalAccessException {

        int s = sheet.size(); // 当前sheet 行数

        List<T> elist = new ArrayList<>();

        List<Object> keyList = sheet.get(keyIndex);

        int ks = keyList.size();

        for (int x = keyIndex + 1; x < s; x++) {

            List<Object> row = sheet.get(x); // 某行数据

            Map<String, Object> emap = new HashMap<>();

            for (int y = 0; y < ks; y++) {

                emap.put(String.valueOf(keyList.get(y)), tryGet(row, y));

            }

            elist.add(map2Bean(emap, sup));

        }

        return elist;

    }

    private List<Map<String, Object>> sheetList2Map(List<List<Object>> sheet , int keyIndex){

        int rowNum = sheet.size();

        // 将每行map的对象存入List

        List<Map<String, Object>> elementList = new ArrayList<>();

        // 暂存指定的key

        List<Object> keyList = sheet.get(keyIndex);

        int keyNum = keyList.size();

        for (int x = keyIndex + 1; x < rowNum; x++) {

            List<Object> row = sheet.get(x);

            Map<String, Object> emap = new HashMap<>();

            elementList.add(emap);

            for (int y = 0; y < keyNum; y++) {

                emap.put(String.valueOf(keyList.get(y)), tryGet(row, y));

            }

        }

        return elementList;

    }

    // 可放于其他工具类

    private <T> T map2Bean(Map<String, Object> map, Supplier<T> sup) throws IllegalAccessException {

        T t = sup.get();

        Field[] fields = t.getClass().getDeclaredFields();

        for (Field field : fields) {

            String fname = field.getName();

            if(!Modifier.isStatic(field.getModifiers())){// 只取非静态对象

                field.setAccessible(true);

                Object o = map.get(fname);

                Class<?> type = field.getType();

                try {

                    if (o != null) {

                        switch (type.getName()) {

                            case "java.lang.String":

                                field.set(t, o.toString());

                                break;

                            case "int":

                                field.set(t, IntegerKit.parseInt(o));

                                break;

                            case "java.lang.Integer":

                                field.set(t, IntegerKit.of(o));

                                break;

                            case "java.time.LocalDateTime":

                                if (o instanceof LocalDateTime) {

                                    field.set(t, o);

                                } else {

                                    field.set(t, LocalDateTime.parse(o.toString(), DateTimeFormatter.ofPattern("yyyy-M-d  HH:mm:ss")));

                                }

                                break;

                            case "double":

                                field.set(t, DoubleKit.parseDouble(o));

                                break;

                            case "java.lang.Double":

                                field.set(t, DoubleKit.of(o));

                                break;

                            case "boolean":

                                field.set(t, BooleanKit.parseBoolean(o));

                                break;

                            case "java.lang.Boolean":

                                field.set(t, BooleanKit.of(o));

                                break;

                            case "float":

                                field.set(t, FloatKit.parseFloat(o));

                                break;

                            case "java.lang.Float":

                                field.set(t, FloatKit.of(o));

                                break;

                            case "short":

                                field.set(t, ShortKit.parseShort(o));

                                break;

                            case "java.lang.Short":

                                field.set(t, ShortKit.of(o));

                                break;

                            case "byte":

                                field.set(t, ByteKit.parseByte(o));

                                break;

                            case "java.lang.Byte":

                                field.set(t, ByteKit.of(o));

                                break;

                            default:

                                break;

                        }

                    } else {

                        System.err.println("data is null");

                    }

                }catch (Exception e){

                    e.printStackTrace();

                    // 打印数据转换错误

                    if (o != null)System.err.println("--->>>>field is " + field.getName() + ", field type is " + type + ",value is " + o + ", value type is " + o.getClass());

                }

            }

        }

        return t;

    }

    /**

    * 引用类型转换为基本类型

    * https://blog.csdn.net/csm_qz/article/details/46853567

    * @param cls

    * @author andus.top

    * @date 2021/6/1 16:08

    */

    private static Class<?> getBasicClass(Class<?> cls){

        if (Integer.class.equals(cls)) {

            return Integer.TYPE; //return int.class;

        }else if(Long.class.equals(cls)){

            return Long.TYPE; // return long.class;

        }else if(Float.class.equals(cls)){

            return Float.TYPE; // return float.class;

        }else if(Boolean.class.equals(cls)){

            return Boolean.TYPE;// return boolean.class;

        }else if(Character.class.equals(cls)){

            return Character.TYPE; // return char.class;

        }else if(Byte.class.equals(cls)){

            return Byte.TYPE; // return byte.class

        }else if(Void.class.equals(cls)){

            return Void.TYPE; // return void.class

        }else if(Short.TYPE.equals(cls)){

            return Short.TYPE; // short.class

        }

        return cls;

    }

    // 可放于其他工具类

    private <T>T tryGet(List<T> list, int index){

        if(list == null || list.size() <= index){

            return null;

        }

        return list.get(index);

    }

    static class IntegerKit {

        public static Integer of(Object o){

            if(o == null){

                return null;

            }

            if(o instanceof Integer){

                return (Integer)o;

            }

            if(o instanceof Number){

                return ((Number)o).intValue();

            }

            return of(o.toString());

        }

        public static Integer of(String s){

            if(s == null || s.isEmpty()){

                return null;

            }

            return Integer.valueOf(s);

        }

        public static int parseInt(String s){

            if(s == null || s.isEmpty()){

                return 0;

            }

            return Integer.parseInt(s);

        }

        public static int parseInt(Object o){

            Integer i = of(o);

            if(i == null){

                return 0;

            }

            return i;

        }

    }

    static class FloatKit {

        public static Float of(Object o){

            if(o == null){

                return null;

            }

            if(o instanceof Float){

                return (Float)o;

            }

            if(o instanceof Number){

                return ((Number)o).floatValue();

            }

            return of(o.toString());

        }

        public static Float of(String s){

            if(s == null || s.isEmpty()){

                return null;

            }

            return Float.valueOf(s);

        }

        public static float parseFloat(String s){

            if(s == null || s.isEmpty()){

                return 0l;

            }

            return Float.parseFloat(s);

        }

        public static float parseFloat(Object o){

            Float f = of(o);

            if(f == null){

                return 0l;

            }

            return f;

        }

    }

    static class DoubleKit {

        public static Double of(Object o){

            if(o == null){

                return null;

            }

            if(o instanceof Double){

                return (Double)o;

            }

            if(o instanceof Number){

                return ((Number)o).doubleValue();

            }

            return of(o.toString());

        }

        public static Double of(String s){

            if(s == null || s.isEmpty()){

                return null;

            }

            return Double.valueOf(s);

        }

        public static double parseDouble(String s){

            if(s == null || s.isEmpty()){

                return 0;

            }

            return Double.parseDouble(s);

        }

        public static double parseDouble(Object o){

            Double d = of(o);

            if(d == null){

                return 0;

            }

            return d;

        }

    }

    static class BooleanKit {

        public static Boolean of(Object o){

            if(o == null){

                return null;

            }

            if(o instanceof Boolean){

                return (Boolean)o;

            }

            return of(o.toString());

        }

        public static Boolean of(String s){

            if(s == null || s.isEmpty()){

                return null;

            }

            return Boolean.valueOf(s);

        }

        public static boolean parseBoolean(String s){

            if(s == null || s.isEmpty()){

                return false;

            }

            return Boolean.valueOf(s);

        }

        public static boolean parseBoolean(Object o){

            Boolean b = of(o);

            if(b == null){

                return false;

            }

            return b;

        }

    }

    static class ByteKit {

        public static Byte of(Object o){

            if(o == null){

                return null;

            }

            if(o instanceof Byte){

                return (Byte)o;

            }

            return of(o.toString());

        }

        public static Byte of(String s){

            if(s == null || s.isEmpty()){

                return null;

            }

            return Byte.valueOf(s);

        }

        public static byte parseByte(String s){

            if(s == null || s.isEmpty()){

                return 0;

            }

            return Byte.parseByte(s);

        }

        public static byte parseByte(Object o){

            Byte b = of(o);

            if(b == null){

                return 0;

            }

            return b;

        }

    }

    static class ShortKit {

        public static Short of(Object o){

            if(o == null){

                return null;

            }

            if(o instanceof Short){

                return (Short)o;

            }

            if(o instanceof Short){

                return ((Short)o).shortValue();

            }

            return of(o.toString());

        }

        public static Short of(String s){

            if(s == null || s.isEmpty()){

                return null;

            }

            return Short.valueOf(s);

        }

        public static short parseShort(String s){

            if(s == null || s.isEmpty()){

                return 0;

            }

            return Short.parseShort(s);

        }

        public static short parseShort(Object o){

            Short s = of(o);

            if(s == null){

                return 0;

            }

            return s;

        }

    }

}

————————————————

                            版权声明:本文 遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。【个人网站: www.andus.top    】


原文链接:https://blog.csdn.net/github_33809414/article/details/118335353

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容