EasyExcel实战:实现导入文件参数校验并记录异常信息

    1.场景问题说明
    2.实现方案以及实现原理简述
    3.demo示例与实现过程

1.场景问题说明

    现要求进行批量导入用户信息,需要对指定参数进行格式校验,参数校验异常的不进行入表操作并进行反馈。注意一次性批量导入,不能因为部分数据参数异常就导致全部入表保存失败。

2.实现方案以及实现原理简述

    easy excel实现批量导入+自定义监听器实现参数校验和异常数据日志打印。
    easy excel按照每行进行读取并进行监听,核心组件 ReadListener监听器源码如下:

public interface ReadListener<T> extends Listener {
   
   // 解析时有异常会触发此逻辑
    default void onException(Exception exception, AnalysisContext context) throws Exception {
        throw exception;
    }

   // 监听解析表头
    default void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {}

    // 监听解析每一行
    void invoke(T data, AnalysisContext context);

  // 额外信息处理
    default void extra(CellExtra extra, AnalysisContext context) {}

   // 监听结束时触发逻辑
    void doAfterAllAnalysed(AnalysisContext context);

  // 判断下一行是否还有数据,即是否需要继续解析
    default boolean hasNext(AnalysisContext context) {
        return true;
    }
}

    easy excel读取的实现原理:每一行进行读取都会进行监听,触发invoke,此处可以自定义实现手机号格式校验逻辑;对于每行读取解析过程中出现异常会触发onException,对手机号异常记录可以实现此方法进行日志输出;所有数据读取完成之后会触发doAfterAllAnalysed,可以实现此方法进行组装数据,方便后续数据库入表操作。

3.demo示例与实现过程

    为方便说明问题,简化业务处理,仅校验手机号是否符合11位.对不符合的记录信息进行日志打印。
    测试文件:test.xls,示例数据截图:
EasyExcel实战:实现导入文件参数校验并记录异常信息_第1张图片
题外话:
    excel 2003与excel 2007区别:首先是后缀不同,03版的后缀为.xls,07版的后缀为.xlsx;后者同时支持两种格式,最大的区别就是存储大小不同,excel 2003最大支持存储的行数为65536,截图如下: EasyExcel实战:实现导入文件参数校验并记录异常信息_第2张图片
;excel 2007最大支持存储的行数为1048576,截图如下: EasyExcel实战:实现导入文件参数校验并记录异常信息_第3张图片
    本文处理的问题和文件格式无关,故此处以excel 2003进行展示说明。
实体类:CustomPerson.java

public class CustomPerson {

    private String name;
    private int age;

    @MoibleValid
    private String mobile;
	
	// 省略get/set
}

自定义手机号校验注解:MobileValid

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MobileValid {
}

自定义监听器:PersonalListener

public class PersonalListener<CustomPerson> implements ReadListener<CustomPerson> {

    private static final Logger log= LoggerFactory.getLogger(PersonalListener.class);

    // 单次处理上限100条记录
    public static int BATCH_COUNT = 100;
   
   // 临时存储数据集合
    private List<CustomPerson> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

   // 自定义消费者函数接口用于自定义监听器中数据组装
    private final Consumer<List<CustomPerson>> consumer;

    public PersonalListener(Consumer<List<CustomPerson>> consumer) {
        this.consumer = consumer;
    }

	// 手机号格式异常日志处理
    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        log.error("异常手机号:{}", exception.getMessage());
    }

	// 每行读取监听触发逻辑
    @Override
    public void invoke(CustomPerson customPerson, AnalysisContext context) throws IllegalAccessException {

        // 手机号格式校验
        validMobile(customPerson);

        cachedDataList.add(customPerson);

		// 按照指定条数对导入数据进行分批处理
        if (cachedDataList.size() >= BATCH_COUNT) {
            consumer.accept(cachedDataList);
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }

    }

    private void validMobile(CustomPerson customPerson) throws IllegalAccessException {
        // 参数校验
        Field[] fields = customPerson.getClass().getDeclaredFields();
        for (Field field : fields) {
            //设置可访问
            field.setAccessible(true);

            //是否手机号格式校验
            boolean ismMbileValid = field.isAnnotationPresent(MobileValid.class);
            if (ismMbileValid) {
                // 手机号值
                String mobileValue = (String) field.get(customPerson);
                if(mobileValue.length() != 11){
                    throw new RuntimeException(mobileValue);
                }
            }
        }
    }
		
	// 所有数据读取解析完成之后触发	
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        if (CollectionUtils.isNotEmpty(cachedDataList)) {
            consumer.accept(cachedDataList);
        }
    }
}

业务处理测试类:PersonalExcel

public class PersonalExcel {

    public static void main(String[] args) {

        ArrayList<CustomPerson> personArrayList = new ArrayList<CustomPerson>();
        // 读取操作
        EasyExcel.read("F:\\test.xls", CustomPerson.class, new PersonalListener<CustomPerson>(
                // 监听器中doAfterAllAnalysed执行此方法;所有读取完成之后处理逻辑
                personList->{
                    for (CustomPerson person:personList){
                        personArrayList.add(person);
                    }
                }
        )).sheet().doRead(); 
        // 读取解析后的文件信息,数据库保存操作忽略
        System.out.println(personArrayList);

    }
}

    easy excel文件读取的方式有多种,此处使用自定义监听器方式实现,更多读取方式参考官方文档,文末附官方文档地址。
    控制台信息如下:

2022-05-01 11:00:17.968 ERROR [main] com.alibaba.easyexcel.test.PersonalTest.PersonalListener:47 - 异常手机号:18523
[CustomPerson{name='张三', age=1, mobile='18523568956'}, CustomPerson{name='王五', age=3, mobile='18523568956'}]

    从控制台可以看出手机号的异常记录已经日志输出,读取的记录中不包含手机号异常记录,至此问题解决,如果还有其他处理方案欢迎评论区留言交流!
    官方文档地址:https://www.yuque.com/easyexcel/doc/easyexcel

你可能感兴趣的:(Easy,Excel,文件导入,参数校验,异常日志打印)