“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);
最终效果图
一定要爱着点儿什么,恰似草木对光阴的钟情。