“validation”校验代码

功能背景:在用户使用导入功能导入大量的数据后,需要对表格的数据进行校验以保证数据的准确性,一般来说,需要校验数据的 长度,非空,格式(手机号,时间)等。

近期在写关于导入功能的时候,遇到了对集合进行校验的功能,特此写下来供大家鉴赏。

首先导入依赖

<dependency>
  <groupId>javax.validation</groupId>
  <artifactId>validation-api</artifactId>
  <version>2.0.1.Final</version>
</dependency>
 
<dependency>
  <groupId>org.hibernate.validator</groupId>
  <artifactId>hibernate-validator</artifactId>
  <version>6.0.20.Final</version>
</dependency>
<dependency>
  <groupId>javax.el</groupId>
  <artifactId>javax.el-api</artifactId>
  <version>3.0.0</version>
</dependency>
<dependency>
  <groupId>org.glassfish.web</groupId>
  <artifactId>javax.el</artifactId>
  <version>2.2.6</version>
</dependency>

创建工具类:

校验属性实体

import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.stream.Collectors;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
 
import com.mocha.sn.base.exception.ExtBusinessException;
/**
 * 校验属性实体.
 * Author:xiehj
 * Date:2023-06-25
 */
public final class ValidationUtils {
     
    private static final Validator VALIDATOR;
     
    private ValidationUtils() { }
     
    static {
        VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator();
    }
     
    /**
     * 检验单个对象,可在前端单条数据保存时使用。
     * @param object 带有@validate的实体类
     * @return 校验结果,全部通过返回null;失败的话,抛出异常ExtBusinessException
     */
    public static String validateEntity(final Object object) {
        final Set<ConstraintViolation<Object>> constraintViolations = VALIDATOR.validate(object);
        if (!constraintViolations.isEmpty()) {
            final String collect = constraintViolations
                .stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.joining(","));
            throw new ExtBusinessException("", String.format("数据校验失败。失败原因:\n%s", collect));
        }
        return null;
    }
     
    /**
     * 校验集合中的每一个数据。
     * @param objectList 校验的集合数据。
     * @param dataValidator 对象的其他校验条件。如手机号格式,时间格式等。
     * <p>
     *      这个方法校验失败会抛出ExtBusinessException异常,使用时需要处理异常,可将异常信息直接返回前端进行展示。
     * </p>
     */
    public static void validateEntity(final List<?> objectList,
                                      final DataValidator<ValidationDto> dataValidator) {
        if (objectList.isEmpty()) {
            return;
        }
         
        final ListIterator<?> iterator = objectList.listIterator();
        while (iterator.hasNext()) {
            final int index = iterator.nextIndex() + 1;
            final Object object = iterator.next();
            final Set<ConstraintViolation<Object>> constraintViolations = VALIDATOR.validate(object);
            if (!constraintViolations.isEmpty()) {
                final String errorMessages = constraintViolations.stream()
                    .map(ConstraintViolation::getMessage)
                    .collect(Collectors.joining(", "));
                throw new ExtBusinessException("", String.format("数据导入失败。失败原因:\n第%s行数据中:%s", index, errorMessages));
            }
            // 能走到这,说明数据注解校验无问题,这里会返回数据的行数及当前实体数据,供调用者进行下一步校验。
            dataValidator.validate(new ValidationDto(index, object));
        }
    }
}

校验数据后返回的类

 

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
 
/**
* 校验数据后返回的类.
* Author:xiehj
* Date:2023-06-25
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ValidationDto {
    /* 数据的行数 */
    private int index;
    /* 实体类数据 */
    private Object obj;
}

 校验函数实现

/**
 * 校验函数实现.
 * Author:xiehj
 * Date:2023-06-25
 */
@FunctionalInterface
public interface DataValidator<ValidationDto> {
     
    void validate(ValidationDto object);
     
}

第一步:

创建实体类,使用注解的方式进行属性的注解。

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
 
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
 
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
 
/**
 * 导入IT日常需求收集实体类.
 * Author:xiehj
 * Date:2023-06-13
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
public class ArticleImportVo {
 
    @NotBlank(message = "标题不能为空")
    @Size(max = 140, message = "标题长度不能超过140个字")
    @ExcelProperty("标题")
    @ColumnWidth(30)
    private String title;
     
    @NotBlank(message = "预计反馈时间不能为空")
    @Size(max = 15, message = "预计反馈时间长度不能超过15个字")
    @ExcelProperty("预计反馈时间")
    @ColumnWidth(20)
    private String entryTime;
     
    @NotBlank(message = "地市不能为空")
    @Size(max = 10, message = "地市长度不能超过10个字")
    @ExcelProperty("地市")
    @ColumnWidth(15)
    private String city;
     
    @NotBlank(message = "部门不能为空")
    @Size(max = 40, message = "部门长度不能超过40个字")
    @ExcelProperty("部门")
    @ColumnWidth(40)
    private String department;
     
    @NotBlank(message = "主管名称不能为空")
    @Size(max = 20, message = "主管名称长度不能超过20个字")
    @ExcelProperty("主管名称")
    @ColumnWidth(20)
    private String supervisorName;
     
    @NotBlank(message = "主管业务角色不能为空")
    @Size(max = 20, message = "主管业务角色长度不能超过20个字")
    @ExcelProperty("主管业务角色")
    @ColumnWidth(30)
    private String businessRole;
     
    @NotBlank(message = "联系方式不能为空")
    @Size(max = 11, message = "联系方式长度不能超过11个字")
    @ExcelProperty("联系方式")
    @ColumnWidth(15)
    private String contactInformation;
     
    @NotBlank(message = "业务模块不能为空")
    @Size(max = 20, message = "业务模块长度不能超过20个字")
    @ExcelProperty("业务模块")
    @ColumnWidth(30)
    private String businessModule;
     
    @NotBlank(message = "现有支撑系统问题及诉求(功能/流程)不能为空")
    @Size(max = 300, message = "现有支撑系统问题及诉求(功能/流程)长度不能超过300个字")
    @ExcelProperty("现有支撑系统问题及诉求(功能/流程)")
    @ColumnWidth(200)
    private String supportSystemIssues;
     
    @NotBlank(message = "督办状态不能为空")
    @Size(max = 5, message = "督办状态长度不能超过5个字")
    @ExcelProperty("督办状态")
    private String urgeToHandle;
     
    @NotBlank(message = "归属项目组不能为空")
    @Size(max = 50, message = "归属项目组长度不能超过50个字")
    @ExcelProperty("归属项目组")
    @ColumnWidth(15)
    private String vestTeam;
}

这个代码中分别使用了:

lombok中的:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
validation中的:
@NotBlank(message = "标题不能为空") // message为如果出现标题这个为空的时候,抛出的异常中出现的文字。
@Size(max = 140, message = "标题长度不能超过140个字") // max = 140, 其中的140是标题的长度,message的长度超过140后,提示的异常文字。
EasyExcel中的:

@ExcelProperty("标题") // 和导入导出的表格表头对应
@ColumnWidth(30) // 导出的表格的宽度

第二步


需要在实现中将获取到的集合数据调用方法。
在注解校验中有些东西无法通过注解进行注释校验,需要写自己的其他校验,则创建下面的方法,传入集合校验的方法中。

final DataValidator<ValidationDto> dataValidator = validation -> {
    // 当前行数据实体
    final ArticleImportVo vo = (ArticleImportVo) validation.getObj();
    // 当前行数
    final int index = validation.getIndex();
    // 进行其他数据校验的逻辑 如果校验失败,抛出异常或者记录错误信息
    if (!TimeValidator.validate(vo.getEntryTime())) {
        throw new ExtBusinessException("", String.format("数据导入失败。失败原因:<br>第%s行数据中:预计反馈时间格式不正确,应该为yyyy-MM-dd",
            index));
    }
    if (!PhoneValidator.validate(vo.getContactInformation())) {
        throw new ExtBusinessException("", String.format("数据导入失败。失败原因:<br>第%s行数据中:联系方式格式不正确", index));
    }
    // 保存ArticleImportVo对象到VO
    supervisorService.save(ReleaseVoConvert.INSTANCE.tosupPo(vo));
};

调用校验方法:

ValidationUtils.validateEntity(list, dataValidator);

最终效果图

 

posted on 2023-07-12 16:49  海哥哥99  阅读(35)  评论(0编辑  收藏  举报

导航