EasyExcel导入数据校验(hibernate-validator)

前言

最近做项目,在使用EasyExcel做数据导入的时候,没有找到什么好的数据校验方法,很多博客都是直接写代码进行校验,感觉很麻烦,因此思考能不能有什么简便的方法。大家都知道web项目,在controller层的方法上加@Validated注解,调用接口的时候会自动进行参数校验,于是思考能不能通过同样的方法对EasyExcel导入的数据进行校验。@Validated是通过hibernate.validator包来实现的,通过看源码,发现javax.validation.ValidatorFactory,通过这个入手,写一个方便的,数据导入校验方法。

思路

Controller层的方法,是spring框架自动调用hibernate校验方法校验,这里我们考虑手动调用hibernate校验方法,既能用hibernate本来自带的一些类似于@NotNull,@NotBlank等注解,也能通过自定义注解扩展@Constraint(validatedBy = { }),用这一套大大提高了代码的复用率。

实现

records是EasyExcel导入定义的实体类list,headNums是表头占的行数

@Slf4j
public class ExcelValidtor {

    public void valid(List records,int headNums)throws ValidException {
        if(records == null || records.size() == 0){
            throw new ValidException(Collections.singletonList(new ErrorMessage(ErrorCode.API,"数据不能为空")));
        }
        HibernateValidatorConfiguration configure = Validation.byProvider(HibernateValidator.class).configure();
        ValidatorFactory validatorFactory = configure.failFast(false).buildValidatorFactory();
        // 根据validatorFactory拿到一个Validator
        Validator validator = validatorFactory.getValidator();
        // 使用validator对结果进行校验
        List errorMsgs = new ArrayList<>();
        for(int a = 0;a> result = validator.validate(records.get(a));
            for(ConstraintViolation constraintViolation:result){
                try {
                    T object = (T)constraintViolation.getLeafBean();
                    ExcelProperty excelProperty = object.getClass().getDeclaredField(constraintViolation.getPropertyPath().toString()).getAnnotation(ExcelProperty.class);
                    String[] value = excelProperty.value();
                    String header = Arrays.stream(value).collect(Collectors.joining(","));
                    ErrorMessage errorMessage = new ErrorMessage(ErrorCode.API,"第"+(headNums+a+1)+"行:"+header+constraintViolation.getMessage());
                    errorMsgs.add(errorMessage);
                } catch (NoSuchFieldException e) {
                    log.error(e.getMessage());
                }
            }
        }
        if (errorMsgs != null && errorMsgs.size() > 0){
            throw new ValidException(errorMsgs);
        }
    }
}

这里的ValidException是自定义的异常类型,其实可以直接用BindException,让全局ExceptionHandler统一处理,这里由于我想加一个列名和行号,所以没这么用。列名通过反射获取@ExcelProperty的属性取得。

@Data
public class ValidException extends Exception{

    private List errorMessages;

    public ValidException(List errorMessages){
        this.errorMessages = errorMessages;
    }

    public ValidException(){}
}
@Getter
@Setter
public class ErrorMessage {

  private String code;

  private String content;

  public ErrorMessage() {
  }

  public ErrorMessage(String code) {
    this(code, null);
  }

  public ErrorMessage(String code, String content) {
    this.code = code;
    this.content = content;
  }

  public static ErrorMessage of(String code, String content) {
    return new ErrorMessage(code, content);
  }
}

调用

try{
	ExcelValidtor excelValidtor = new ExcelValidtor();
	excelValidtor.valid(uploadRecords,1);
}catch (ValidException e) {
}

效果

{
  "code": "1000",
  "content": "第2行:姓名不能为null"
},
{
  "code": "1000",
  "content": "第3行:姓名不能为null"
},
{
  "code": "1000",
  "content": "第3行:年龄不能为null"
},
{
  "code": "1000",
  "content": "第3行:住址不能为null"
}

问题

目前这块,我感觉行数的计算可能会有点问题,因为没有确认过,EasyExcel的导入,空行会不会给空数据,如果是直接忽略空行的话,行数就会错误。等后续有时间再确认。

你可能感兴趣的:(java,hibernate,java,spring)