java将复杂Excel表格转为实体类对象,表格中有合并单元格数据

        在工作中,需要处理大量的表格数据,而且我并没有找到能够一键转换的工具,于是自己写了一个转化工具函数。

        Excel表格

以下的代码是基于Hutool工具中的Excel工具实现的,因此需要先导入Hutool包,可以按需导入,

具体参考Hutool官网简介 | Hutool

<dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.1.2</version>
        </dependency>

实体类

需要注意的是,实体类中的属性顺序应当与Excel表格属性的顺序相同,否则无法正确赋值,如果要设置表格中没有的属性,应当将该属性放置最下方,如Student的ID所示。然后对返回数据再进行处理。

package io.renren.modules.tollstation.utils;

import lombok.Data;

import java.math.BigDecimal;
import java.util.Date;

/**
 * @author 李亚杰
 * @date 2024/4/24 11:30
 * @description Student
 */
@Data
public class Student {
    private String name;
    private Long age;
    private Date birthday;
    private BigDecimal money;
    private Long id;
}

在Excel工具读取中,数字类型会转化为Integer类型,小数会转化为Double类型,因此,如果实体类与这两种类型不同,则需要再做处理。

package io.renren.modules.tollstation.utils;


import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

import java.util.*;

/**
 * @author 李亚杰
 * @111 2024/4/24 9:05
 * @description LiyajieExcelUtil
 */
public class LiyajieExcelUtil {


    public static void main(String[] args) throws Exception {
//        File file = new File("C:\\Users\\liyajie\\IdeaProjects\\monthScore\\renren-admin\\src\\main\\resources\\2023年通行费收入统计表-税前(公司、路段)20240116.xlsx");
//       File file = new File("C:\\Users\\liyajie\\IdeaProjects\\monthScore\\1713861968509.xlsx");
        File file = new File("C:\\Users\\liyajie\\IdeaProjects\\monthScore\\renren-admin\\src\\main\\resources\\学生.xlsx");
        dispose(file,1,1,0,1000, Student.class).forEach(System.out::println);
    }

    /**
     * 将Excel转换为实体类集合
     * @param file          excel文件
     * @param sheetIndex    sheet索引
     * @param startIndex    起始行数(忽略前几行),一般需要忽略到属性名之前
     * @param endIndex      结束行数(忽略最后几行)
     * @param size          集合初始容量(由于ArrayList自动扩容耗费时间,应指定初始容量)
     * @param tClass        转换的实体类class对象
     * @return
     * @param <T>
     */
    public static <T> List<T> dispose(File file, int sheetIndex,int startIndex,int endIndex,int size,Class<T> tClass){
        //用于存储合并单元格的数据
        Map<Integer,Object> tempMap = new HashMap<>();
        //创建指定初始大小的集合
        List<T> list = new ArrayList<>(size);
        ExcelReader reader = ExcelUtil.getReader(file,sheetIndex-1);
        List<List<Object>> read = reader.read();
        //对集合进行分割,去除开始之前的数据和最后的数据
        read = read.subList(startIndex,read.size()-endIndex);
        read.forEach(o->{
            for (int i = 0; i < o.size(); i++) {
                String s = StrUtil.toString(o.get(i));
                //如果该列的属性值不为空,则放入集合
                if (StrUtil.isNotBlank(s)){
                    tempMap.put(i,s);
                }else {
                    //为空,则从集合中取出上一次存储的值
                    o.set(i,tempMap.get(i));
                }

            }
            try {
                //将处理后的List<Object>对象转换为实体对象
                T t = listObjToEntity(o, tClass);
                list.add(t);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

        });
        //关闭流
        reader.close();
        return list;
    }

    /**
     * 将List<Object>转换为实体对象
     * @param listObj  List<Object>对象  其中是实体对象的属性值
     * @param tClass    实体的Class对象
     * @return 实体对象
     * @param <T>
     * @throws Exception
     */
    public static <T> T listObjToEntity(List<Object> listObj,Class<T> tClass) throws Exception {
        //通过反射创建对象
        Constructor<T> constructor = tClass.getConstructor();
        T entity = constructor.newInstance();
        for (int i = 0; i < listObj.size(); i++) {
            //获取对象的属性
            Field field = tClass.getDeclaredFields()[i];
            field.setAccessible(true);
            //获取对象的属性值
            Object o = listObj.get(i);
            //获取属性值的Class对象
            Class<?> type = field.getType();
            if (o!=null){
                //将属性值转换为实体类中需要的数据类型
                o = objToAttribute(o,type);
            }
            //设置属性值
            field.set(entity,o);

        }
        return entity;
    }

    /**
     * 将任意数据类型转换为自己需要的数据类型
     * @param o  Object数据类型
     * @param type 需要的数据类型的Class对象
     * @return 转换后的对象
     * @param <T>
     * @throws Exception
     */
    public static <T> T objToAttribute(Object o,Class<T> type)   {
        Object o1;
        try {
            //如果需要的类型为为字符串,则不需要额外处理
            if(type==String.class){
                return (T)o;
            }
            if (type!= Date.class) {
                //通过反射创建对象并赋值
                //日期无法通过字符串生成,但是在读取Excel时已经自动转成Date对象了,所以对日期不需要处理
                Constructor<?> constructor = type.getDeclaredConstructor(String.class);
                constructor.setAccessible(true);
                o1 = constructor.newInstance(o.toString());
            }else {
                o1 = o;
            }
        } catch (Exception e) {
            throw new RuntimeException("非法转换");
        }
        return (T) o1;
    }

}

测试结果

希望本篇文章能帮助大家解决一下问题。

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

财大彭于晏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值