- 前言
- 一、代码
- 二、使用
- 二、结束
前言
我们在使用EasyExcel做导入功能时,通过在实体或者VO加@ExcelProperty(“测试”)注解来实现列的一一对应,read()之后获取一个List
的结果集,得到java的数据类型然后在进行业务操作
但EasyExcel这种通过注解的方式实现导入就必须使用事先定义好数据类型来接收,它不支持对象中的子对象,也不能导入excel带有动态列的数据(即相同列名下的多个数据列)
换做java的数据结构即如下结构:
这里使用原生的EasyExcel并不能接收到多个列名为 测试1 的数据
这里提供一种解决方式,它能够实现动态列的解析,实例化对象中的子对象这种数据结构(仅支持二级的嵌套,即一对多的这种关系)
一、代码
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ExcelDynamic {
}
public class DynamicReadListener extends AnalysisEventListener
public class Excels extends EasyExcel{
private Excels() {}
public static List imports(InputStream fileStream, Class clazz){
return read(fileStream).head(clazz).sheet().doReadSync();
}
public static List importsDynamic(InputStream fileStream, Class clazz) throws IllegalAccessException, InstantiationException {
//初始化 处理动态列 readListener
DynamicReadListener dynamicReadListener = DynamicReadListener.init();
//初始化 同步读取数据 readListener
SyncReadListener syncReadListener = new SyncReadListener();
ExcelReaderSheetBuilder sheet = read(fileStream).useDefaultListener(false).head(clazz).sheet();
sheet.registerReadListener(dynamicReadListener);
//注册 map转 model readListener
sheet.registerReadListener(new ModelBuildEventListener());
sheet.registerReadListener(syncReadListener);
sheet.doRead();
return build((List) syncReadListener.getList(), dynamicReadListener);
}
private static List build(List targets, DynamicReadListener listener) throws IllegalAccessException, InstantiationException {
if (CollectionUtils.isNotEmpty(targets)){
for (int i = 0; i < targets.size(); i++) {
T target = targets.get(i);
// 初始化带有 @ExcelDynamic 标志的属性
for (Field targetField : target.getClass().getDeclaredFields()) {
if (Objects.nonNull(targetField.getAnnotation(ExcelDynamic.class))){
targetField.setAccessible(true);
targetField.set(target, build(listener.getDynamicColumns().get(i), targetField.getType()));
}
}
}
}
return targets;
}
private static T build(Map> dynamicRow, Class clazz) throws InstantiationException, IllegalAccessException {
if (Objects.isNull(clazz)){
throw new NullPointerException("class not support null value");
}
//处理类型属性list
Field[] fields = clazz.getDeclaredFields();
//待处理命中动态列数据
Map> hitColumn = new HashMap<>(fields.length);
//开始筛选命中动态列
dynamicRow.forEach((head, columns)->{
//遍历 属性
for (Field field : fields) {
//获取属性注解
ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
if (Objects.nonNull(annotation)){
//根据注解值匹配
Object[] annotationKeys = annotation.value();
for (Object annotationKey : annotationKeys) {
if (!Objects.equals("", annotationKey) && Objects.equals(head, annotationKey)){
if (CollectionUtils.isNotEmpty(columns)){
hitColumn.put(field, columns);
break;
}
}
}
}
}
});
return handle(hitColumn, clazz);
}
private static T handle(Map> hitColumn, Class clazz) throws InstantiationException, IllegalAccessException {
//处理返回结果
if(CollectionUtils.isNotEmpty(hitColumn.keySet())){
T target = clazz.newInstance();
hitColumn.forEach((field, columns) -> {
try {
List
二、使用
文件数据
测试
@Test
public void test1() throws FileNotFoundException, IllegalAccessException, InstantiationException {
List as = Excels.importsDynamic(new FileInputStream(new File("C:\Users\caobinghui\Desktop\test.xlsx")), A.class);
as.forEach(System.out::println);
}
结果
代码拙劣,大家可以自己去试着优化
觉得有帮助的可以点个赞,谢谢!!



