专栏名称: 码农小胖哥
技术公众号:码农小胖哥
目录
相关文章推荐
寿光报  ·  医生紧急提醒!它是全民减肥绊脚石 ·  16 小时前  
羊城派  ·  杨国福麻辣烫食品柜出现老鼠?官方通报 ·  19 小时前  
羊城派  ·  杨国福麻辣烫食品柜出现老鼠?官方通报 ·  19 小时前  
中国药闻  ·  李强主持召开国务院常务会议 ... ·  23 小时前  
51好读  ›  专栏  ›  码农小胖哥

导入Excel还得每个字段做校验?搞定它 | Java Debug 笔记

码农小胖哥  · 掘金  ·  · 2021-05-11 22:54

正文

阅读 163

导入Excel还得每个字段做校验?搞定它 | Java Debug 笔记

本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看 活动链接

最近在做Excel导入功能,产品要求对导入数据先进行校验然后再入库。于是简单封装了一个工具,结果兄弟们用了都说好,今天就把思路分享出来。

easyexcel 库

我们都知道 POI 是Java操作Excel的基础库。为了通用性并没有做定制,而且还有一些局限性。经过一番调研决定采用二次封装库 easyexcel 来进行业务开发。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>${easyexcel.version}</version>
</dependency>
复制代码

easyexcel 将读取Excel的生命周期抽象为了几个阶段,方便我们在各个阶段注入你想要实现的逻辑。 这几个阶段包含在 ReadListener 接口中

public interface ReadListener<T> extends Listener {
    /**
     * 当任何一个侦听器执行错误报告时,所有侦听器都将接收此方法。 如果在此处引发异常,则整个读取将终止。
     * 这里是处理读取excel异常的
     *
     * @param exception
     * @param context
     * @throws Exception
     */
    void onException(Exception exception, AnalysisContext context) throws Exception;

    /**
     * 读取每行excel表头时会执行此方法
     *
     * @param headMap
     * @param context
     */
    void invokeHead(Map<Integer, CellData> headMap, AnalysisContext context);

    /**
     * 读取每行数据的时候回执行此方法 
     *
     * @param data
     *            one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     *            analysis context
     */
    void invoke(T data, AnalysisContext context);

    /**
     * 如果有额外的单元格信息返回就用此方法处理
     *
     * @param extra
     *            extra information
     * @param context
     *            analysis context
     */
    void extra(CellExtra extra, AnalysisContext context);

    /**
     * 在整个excel sheet解析完毕后执行的逻辑。
     *
     * @param context
     */
    void doAfterAllAnalysed(AnalysisContext context);

    /**
     * 用来控制是否读取下一行的策略
     *
     * @param context
     * @return
     */
    boolean hasNext(AnalysisContext context);
}
复制代码

其抽象实现 AnalysisEventListener<T> 提供更加符合需要的抽象,我会进一步实现这个抽象来实现Excel的导入和校验。

在你了解一个框架的抽象接口后,尽量要去看一下它有没有能满足你需要的实现。

另外这里要多说一点,接口中的 AnalysisContext 包含了很多有用的上下文元信息,比如 当前行、当前的配置策略、excel整体结构等信息,你可以在需要的时候调用这些信息。

JSR303校验

最开始自己写了一个抽象的校验工具,最后发现每一个字段都要编写其具体的校验逻辑,如果一个Excel的字段量爆炸,这对开发来说就可能是噩梦。这使我想到了业界已经有的规范- JSR303 校验规范,它将数据模型(Model)和校验(Validation)各自抽象,非常灵活,而且工作量明显降低。我们只需要找到和 esayexcel 生命周期结合的地方就行了。我们只需要引入以下依赖就能在Spring Boot项目中集成JSR303校验:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
复制代码

关于JSR303相关的教程可以查看我另一篇文章

思路

我们可以在解析每个字段的时候校验,这对应 ReadListener invoke(T data, AnalysisContext context) 方法,这种方式可以实现当字段校验触发约束时就停止excel解析的策略;另一种可以在Excel解析完毕后执行校验,对应 doAfterAllAnalysed(AnalysisContext context) 。这里以第二种为例我们来实现一下。

我们在编写代码时,尽量职责单一,一个类或者一个方法尽量只干一个事,这样让自己的代码足够清晰。

编写校验处理类

这里我把解析和校验分开实现,先编写JSR303校验工具。这里假设已经有了校验器 javax.validation.Validator 的实现, 稍后我会讲这个实现从哪里注入

import cn.felord.validate.Excel;
import lombok.AllArgsConstructor;
import org.springframework.util.StringUtils;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.util.*;
import java.util.stream.Collectors;

/**
 *  excel 校验工具
 *
 * @param <T> the type parameter
 * @author felord.cn
 * @since 2021 /4/14 14:14
 */
@AllArgsConstructor
public class ExcelValidator<T> {

    private final Validator validator;
    private final






请到「今天看啥」查看全文