以下代码是一个Excel数据监听器,用于监听和处理Excel数据的读取事件。它实现了AnalysisEventListener接口,并重写了其中的方法。以下是代码中的主要部分:
- invokeHead方法:在解析Excel表格的表头时触发的回调方法。通过比较模板表头和当前上传文件的表头,检查表头的合法性。
- invoke方法:在解析Excel表格的数据行时触发的回调方法。在这个方法中可以处理每一行的数据逻辑。
- onException方法:当解析过程中发生异常时触发的回调方法。如果是Excel数据转换异常,则会记录日志并抛出自定义的BizException异常。其他异常会直接抛出。
- doAfterAllAnalysed方法:当整个Excel表格解析完成时触发的回调方法。在这个方法中可以进行数据处理、数据存储、数据校验等业务逻辑的处理。
- getDataList方法:用于获取解析过程中的数据行信息。
- readTemplateHeader方法:用于读取Excel模板的表头。
这段代码的作用是根据传入的Excel模板路径和文件名,解析Excel文件,并进行表头校验和数据行处理,文章中只处理了按照模板校验表头是否合法,针对动态传入List
形式的表头可自行扩展
/*** Excel数据监听器,用户监听和处理Excel数据的读取事件* 实现了EasyExcel库的AnalysisEventListener接口,实现了相应的回掉方法** @author 管理员* @date 2024/2/27* @param <T> 要解析的Excel数据对象的类型*/
@Slf4j
public class ExcelListener < T > extends AnalysisEventListener < T > {/*** 文件特殊字符规则*/private static final String FILE_SPECIAL_REGEX = "[\\/:*?\"<>|;.]";/*** 用于存储解析过程中数据行信息*/private final List < T > dataList = Lists.newArrayList();/*** Excel模板路径(此实现是resource路径)*/private String templatePath;/*** 模板表头集合*/private List < String > templateHeaderList;/*** Excel数据监听器构造方法** @author 管理员* @date 2024/3/4*/public ExcelListener() {}/*** Excel数据监听器构造方法,此构造方法会校验表头是否合法【注意】:此方法默认为第一行为表头,如不是请重写构造方法传入表头对应行数** @author 管理员* @date 2024/3/4* @param templatePath 模板路径(resource路径)*/public ExcelListener(String templatePath) {this.templatePath = templatePath;this.templateHeaderList = readTemplateHeader();}/*** Excel数据监听器构造方法,此构造方法会校验表头是否合法,文件名称非法* 【注意】:此方法默认为第一行为表头,如不是请重写构造方法传入表头对应行数** @author 管理员* @date 2024/3/4* @param templatePath 模板路径(resource路径)* @param excelFileName 上传Excel文件名称* @throws BizException 业务异常*/public ExcelListener(String templatePath, String excelFileName) {// 文件名不能包含特殊字符if (ReUtil.contains(FILE_SPECIAL_REGEX, FileNameUtil.mainName(excelFileName))) {throw new BizException("业务错误码","误码提示");}// 判断文件后缀是否是Excel 文件格式错误if (!ReUtil.isMatch("(xlsx|xls)$", FileNameUtil.extName(excelFileName).toLowerCase())) {throw new new BizException("业务错误码","误码提示");}this.templatePath = templatePath;this.templateHeaderList = readTemplateHeader();}@Overridepublic void invokeHead(Map < Integer, CellData > headMap, AnalysisContext context) {// 当解析Excel表格的表头时触发的回调方法,此处可在类中添加成员变量,校验表头合法性// invokeHead抛出异常只会终止当前invokeHead方法的执行,可在OnException中处理并终止程序// headMap存储所有表头信息,可与成员变量对比,不一致则不合法// 未传入模板路劲则表示无须对比模板表头,直接调用默认父类方法if (CharSequenceUtil.isBlank(templatePath)) {super.invokeHead(headMap, context);return;}// 模板表头无内容表示模板错误if (CollUtil.isEmpty(templateHeaderList)) {throw new BizException("业务错误码","误码提示");}List < String > currentHeaderList = Lists.newArrayListWithCapacity(headMap.size());headMap.forEach((columnIndex, cellData) -> currentHeaderList.add(cellData.getStringValue()));// 比较模板的表头与当前上传文件的表头,如果两个表头不一致则表示模板错误,抛出异常if (!CollUtil.isEqualList(templateHeaderList, currentHeaderList)) {throw new BizException("业务错误码","误码提示");}// 无任何异常执行直接调用默认父类方法super.invokeHead(headMap, context);}@Overridepublic void invoke(T rowData, AnalysisContext analysisContext) {// 当解析Excel表格的数据行时触发的回调方法,在这个方法中可以处理每一行的数据逻辑dataList.add(rowData);}@Overridepublic void onException(Exception exception, AnalysisContext context) {// onException抛出异常会终止解析,并在最外层可捕获该异常// 解析过程中发生异常的逻辑,一般记录日志if (exception instanceof ExcelDataConvertException) {ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;StringBuilder stringBuffer = new StringBuilder();stringBuffer.append("第").append(excelDataConvertException.getRowIndex()).append("行,").append(excelDataConvertException.getColumnIndex()).append("列解析异常").append("异常数据为:").append(excelDataConvertException.getCellData()).append("异常列属性为:").append(excelDataConvertException.getExcelContentProperty().getHead());log.error(stringBuffer.toString());throw new BizException("业务错误码",stringBuffer.toString());}else if (exception instanceof BizException) {throw (BizException) exception;}}@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {// 当整个Excel表格解析完成时触发的回调方法,解析完毕之后一般有以下逻辑处理// 数据处理、数据存储、数据校验、业务通知// 逻辑1:当dataList为空,标识文件中没有数据行,可以认为是一个人空模板if (CollUtil.isEmpty(dataList)) {throw new BizException("业务错误码","误码提示");}}/*** 获取解析过程中的数据行信息** @author 管理员* @date 2024/2/27* @return 数据行信息*/public List < T > getDataList() {return dataList;}/*** 读取Excel模板表头** @author 管理员* @date 2024/3/4* @return Excel模板表头* @throws BizException 业务异常*/private List < String > readTemplateHeader() {// 无模板路径不解析模板表头if (CharSequenceUtil.isBlank(templatePath)) {return Lists.newArrayList();}try (InputStream inputStream = ResourceUtil.getStreamSafe(templatePath)) {List < Map < Integer, String > > headList = EasyExcelFactory.read(inputStream).headRowNumber(0).sheet().doReadSync();// 读取表头不为空,只要模板没问题,肯定不会空if (CollUtil.isNotEmpty(headList)) {Map < Integer, String > headMap = headList.get(0);List < String > headerList = Lists.newArrayListWithExpectedSize(headMap.size());headMap.forEach((key, value) -> headerList.add(value));return headerList;}}catch (IOException ex) {log.error("读取Excel模板表头异常", ex);throw new BizException("业务错误码","误码提示");}return Lists.newArrayList();}
}
方式一:表头文件什么的都不做任何校验
ExcelListener < T > excelListener = new ExcelListener <>();
方式二:此种方式只校验表头
ExcelListener < T > excelListener = new ExcelListener <>(templatePath);
方式三:最后这种方式校验表头与文件的合法性
ExcelListener < T > excelListener = new ExcelListener <>(templatePath,fileName);
excelListener 传入EasyExcelFactory中实现文件解析并转换为对应实体对象
EasyExcelFactory.read(inputStream, clazz, excelListener).sheet().doRead();
总而言之,该Excel数据监听器可以帮助用户高效、准确地解析和处理Excel数据。它提供了表头校验、数据处理和异常处理等功能,使得数据的导入和处理变得更加简单和可靠。无论是处理大规模数据还是进行数据校验,该监听器都能够帮助用户提升工作效率,减少错误率。