1.场景问题说明
2.实现方案以及实现原理简述
3.demo示例与实现过程
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,可以实现此方法进行组装数据,方便后续数据库入表操作。
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