SpringBoot基础之参数validator校验

564 阅读5分钟

这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

前言

在我们应用程序的业务逻辑中,经常会碰到参数校验的情况,手动的在代码层上面进行校验就会带来很不好的体验,验证代码繁琐,方法内代码显得冗长且和业务逻辑关系不大,维护的成本较高。因此有了这个Java Validation API(JSR 303)。而我们使用的Hibernate Validator是JSR 303标准的一个具体实现,用于对参数进行合法性校验。

使用

(一) 集成

springboot 2的web'项目中默认集成spring-boot-starter-validation ,直接使用即可

其他版本可能需要添加validation-api,hibernate-validator依赖

(二) 使用

1. 注解使用

在Bean类中的需要的属性字段上添加对应的注解

@Data
public class StudentGroupDto {

    //主键id
    @Null(message = "id必须为空", )
    private Long id;

    //姓名
    @NotEmpty(message = "姓名不能为空")
    @Length(min =2, message = "姓名长度应大于{min}位")
    @Length(max =20, message = "姓名长度应小于{max}位")
    private String name;
}

在controller证明需要验证的bean

   @RequestMapping("/save")
    public ResultVo save(@Validated StudentGroupDto studentGroupDto) {
        return ResultVo.success();
    }

在请求的时候如果参数验证不通过则直接抛出BindException异常,这个异常我们通常不会直接返回到前端,需要在全局异常捕获中处理成,我们需要的格式,处理方法

 @ExceptionHandler(value = org.springframework.validation.BindException.class)
    public ResultVo bindExceptionHandle(BindException ex){
        log.info("用户数据参数异常: {}",ex);
        StringBuffer defaultMessage = new StringBuffer("参数异常");
        List<ObjectError> list = ex.getBindingResult().getAllErrors();
        if(list!=null && list.size()>0){
            defaultMessage.append(":")  ;
            try {
                int i=0;
                for (ObjectError error : list) {
                    if(i>0){  defaultMessage.append(",");  }
                    defaultMessage.append(error.getDefaultMessage());
                    i++;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return ResultVo.fail(defaultMessage.toString());
    }

2. 方法调用使用

构造validator对象

private static  validator = Validation.buildDefaultValidatorFactory().getValidator();

public static void validateEntity(Object object, Class<?>... groups)
            throws RRException {
        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
        if (!constraintViolations.isEmpty()) {
            StringBuilder msg = new StringBuilder();
            for(ConstraintViolation<Object> constraint:  constraintViolations){
                msg.append(constraint.getMessage()).append("<br>");
            }
            throw new Exception(msg.toString());
        }
    }
    

调用validateEntity方法验证,如果验证错误直接抛出异常

(三) 约束条件解释

在idea的BeanValidation中的constraints能看到所有的约束条件

注解解释
@Null被注释的元素必须为 null
@NotNull被注释的元素必须不为 null
@NotBlank 验证字符串非null,且长度必须大于0
@NotEmpty被注释的元素的必须非空
@Length(min=,max=)被注释的字符串的大小必须在指定的范围内,如果为null不验证
@Range(min=,max=,message=)被注释的元素必须在合适的范围内
@AssertTrue被注释的元素必须为 true
@AssertFalse被注释的元素必须为 false
@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max=, min=)被注释的元素的大小必须在指定的范围内
@Email被注释的元素必须是电子邮箱地址
@Digits (integer, fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past被注释的元素必须是一个过去的日期
@Future被注释的元素必须是一个将来的日期
@FutureOrPresent 判断日期是否是将来或现在日期
@Pattern(regex=,flag=)被注释的元素必须符合指定的正则表达式

(四) 验证组的使用

在不同的业务中,对于一个bean中需要的字段可能不同,如果只是使用默认的验证组Default.class(不添加groups 就是使用的Default.class)

例子

@NotNull(message = "缺少必要的参数", groups ={IdGroup.class})
private Long id;

@NotBlank(message = "缺少物料编号", groups = {AddGroup.class})
private String productCode;

@NotBlank(message = "缺少物料编号", groups = {AddGroup.class})
private String productCode;

@NotEmpty(message = "缺少行项目信息")
@Valid
private List<PcoUnripeContractScopeEntity> details;

1. 验证groups包含IdGroup.class的参数

public interface IdGroup {
}

2. 验证groups包含AddGroup.class的参数 和不包含groups信息的参数

public interface AddGroup extends Default {
}

3. 验证groups包含AddGroup.class和IdGroup.class的参数 和不包含groups信息的参数 ,且当前一个验证组验证失败的情况下,不会继续验证后续验证组

@GroupSequence({AddGroup.class, IdGroup.class})
public interface Group {
}

(五) @Valid和和@Validated

  1. @Valid注解用于校验,所属包为:javax.validation.Valid

  2. @Validated是@Valid 的一次封装,是Spring提供的校验机制使用

  3. @Validated提供分组验证功能

  4. @Valid不提供分组验证功能,不支持分组的,只要groups存在费Default.class的 验证组,则不会验证该规则

  5. @Valid可以使用在对象中的集合属性上,对该集合中对象数据进行校验

(六) 其他

1.快速失败模式

Spring Validation默认会校验完所有字段,然后才抛出异常。通过一些简单的配置,开启Fali Fast模式,一旦校验失败就立即返回

        ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
                .configure()
                .failFast(true)
                .buildValidatorFactory();
        Validator validator = validatorFactory.getValidator();

2.和代码生成器一起使用(volicity版)

原来

#foreach ($column in $columns)
@ApiModelProperty(value="$column.comments",name="$column.attrname",required=false)
	private $column.attrType $column.attrname;
	#end
#end

添加后


#foreach ($column in $columns)
#if($column.attrname=='id')
	@NotNull(message = "缺少必要的参数",groups = {IdGroup.class})#end
#if($column.attrname !='id' && $column.attrType =='String' )
	@NotBlank(message = "缺少$column.comments",groups = {AddGroup.class})#end
#if($column.attrname !='id' && $column.attrType !='String' )
	@NotNull(message = "缺少$column.comments",groups = {AddGroup.class})#end
	@ApiModelProperty(value="$column.comments",name="$column.attrname",required=false)
	private $column.attrType $column.attrname;
	#end
#end

3.警告

注意不要过度使用验证,只需要基础验证就行了,否则就会出现,写的时候爽,创建了各种groups, 改的时候难受的要死

    作者:ZOUZDC
    链接:https://juejin.cn/post/7028963866063306760
    来源:稀土掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。