在工作中,需要处理大量的表格数据,而且我并没有找到能够一键转换的工具,于是自己写了一个转化工具函数。
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;
}
}
测试结果
希望本篇文章能帮助大家解决一下问题。