其抽象实现AnalysisEventListener
在你了解一个框架的抽象接口后,尽量要去看一下它有没有能满足你需要的实现。
另外这里要多说一点,接口中的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 Integer beginIndex;
- /**
- * 集合校验
- *
- * @param data 待校验的集合
- * @return list
- */
- public List<String> validate(Collection<T> data) {
- int index = beginIndex + 1;
- List<String> messages = new ArrayList<>();
- for (T datum : data) {
- String validated = this.doValidate(index, datum);
- if (StringUtils.hasText(validated)) {
- messages.add(validated);
- }
- index++;
- }
- return messages;
- }
- /**
- * 这里是校验的根本方法
- *
- * @param index 本条数据所在的行号
- * @param data 待校验的某条数据
- * @return 对数据的校验异常进行提示,如果有触发校验规则的会封装提示信息。
- */
- private String doValidate(int index, T data) {
- // 这里使用了JSR303的的校验器,同时使用了分组校验,Excel为分组标识
- Set<ConstraintViolation<T>> validate = validator.validate(data, Excel.class);
- return validate.size()>0 ? "第" + index +
- "行,触发约束:" + validate.stream()
- .map(ConstraintViolation::getMessage)
- .collect(Collectors.joining(",")): "";
- }
- }
上面就是整个校验的逻辑,如果校验通过不提示任何信息,如果校验不通过把校验的约束信息封装返回。这里的Validator是从哪里来的呢?当Spring Boot集成了JSR303会有一个Validator实现被自动注入Spring IoC,我们可以利用它。
实现AnalysisEventListener
这个完全是easyexcel的功能了,我们只需要实现最开始提到的Excel抽象解析监听器接口AnalysisEventListener,并将解析字段加入集合,等完全解析完毕后再进行校验。这里如果校验不通过就会抛出携带校验信息的异常,异常经过处理返回前端提示。
切记:AnalysisEventListener的实现不能注入Spring IoC。