后端验证框架-Hibernate validation

1. 引入依赖


<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.17.Final</version>
</dependency>

2. 配置全局捕获异常处理


@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public Object handleBindException(BindException ex) {
        log.info("BindException",ex);
        StringBuilder errorMsg = new StringBuilder();
        // 获取所有字段验证出错的信息
        List<FieldError> allErrors = ex.getFieldErrors();
        allErrors.forEach(fieldError -> errorMsg.append(fieldError.getField())
        .append(":").append(fieldError.getDefaultMessage()).append("; "));
        return ResultModel.error(ResultStatus.FAIL_ERR, errorMsg.toString());
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.info("MethodArgumentNotValidException",ex);
        StringBuilder errorMsg = new StringBuilder();
        // 获取所有字段验证出错的信息
        List<FieldError> allErrors = ex.getFieldErrors();
        allErrors.forEach(fieldError -> errorMsg.append(fieldError.getField())
        .append(":").append(fieldError.getDefaultMessage()).append("; "));
        return ResultModel.error(ResultStatus.FAIL_ERR, errorMsg.toString());
    }
}

3. 常用的验证注解


@Data
public class AddUserDTO {

    @NotBlank(message = "姓名不能为空")
    @Size(max = 20, message = "姓名的长度不能超过20")
    @ApiModelProperty(value = "姓名",required = true)
    private String name;

    @NotNull
    @Pattern(regexp = "^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$", message = "请输入正确的手机号")
    @ApiModelProperty(value = "手机号",required = true)
    private String phone;

    @Max(value = 10, message = "年龄不能超过10岁")
    @Min(value = 1, message = "年龄不能低于1岁")
    @ApiModelProperty("年龄")
    private Integer age;

    @ApiModelProperty("性别")
    private Integer sex;

    @ApiModelProperty("地址")
    private String address;

    @NotEmpty(message = "请选择所要管理的加油站")
    @ApiModelProperty(value = "加油站id集合",required = true)
    private List<Integer> gasStationIds;

    @NotNull(message = "请选择用户角色")
    @ApiModelProperty(value = "用户角色类型,0-站长,1-员工,2-运维", required = true)
    private Integer role;
    
}

4. 注意事项


//实体类里的参数验证需要加上@Valid或@Validated注解
public Object create(@RequestBody @Valid AddUserDTO dto){}

//参数直接加注解就行
public Object create(@NotNull String str){}

//注解说明
@AssertFalse @AssertTrue  检验boolean类型的值

@DecimalMax @DecimalMin  限定被标注的属性的值的大小

@Digits(intege=,fraction=) 限定被标注的属性的整数位数和小数位数

@Future检验给定的日期是否比现在晚

@Past    校验给定的日期是否比现在早

@Max检查被标注的属性的值是否小于等于给定的值

@Min检查被标注的属性的值是否大于等于给定的值

@NotNull检验被标注的值不为空

@Null     检验被标注的值为空

@Pattern(regex=,flag=)  检查该字符串是否能够在match指定的情况下被regex定义的正则表达式匹配

@Size(min=,max=)  检查被标注元素的长度

@Valid递归的对关联的对象进行校验

5.validator 注解


 1. 空与非空检查
 
|注解       |支持Java类型                            |说明
|@Null	    |Object                                 |为null
|@NotNull	|Object                                 |不为null
|@NotBlank	|CharSequence	                        |不为null,且必须有一个非空格字符
|@NotEmpty	|CharSequence、Collection、Map、Array	|不为null,且不为空(length/size>02. Boolean值检查
 
|注解	        |支持Java类型	      |说明	       |备注
|@AssertTrue	|boolean、Boolean	  |为true	   |为null有效
|@AssertFalse	|boolean、Boolean	  |为false	   |为null有效

 3. Boolean值检查
 
|注解	        |支持Java类型	      |说明	       |备注
|@AssertTrue	|boolean、Boolean	  |为true	   |为null有效
|@AssertFalse	|boolean、Boolean	  |为false	   |为null有效

4. 日期检查
 
|注解	         |支持Java类型	        |说明	             |备注
|@Future	     |Date、Calendar、Instant、LocalDate、LocalDateTime、LocalTime、MonthDay、OffsetDateTime、OffsetTime、Year、YearMonth、ZonedDateTime、HijrahDate、JapaneseDate、MinguoDate、ThaiBuddhistDate|验证日期为当前时间之后|为null有效
|@FutureOrPresent|Date、Calendar、Instant、LocalDate、LocalDateTime、LocalTime、MonthDay、OffsetDateTime、OffsetTime、Year、YearMonth、ZonedDateTime、HijrahDate、JapaneseDate、MinguoDate、ThaiBuddhistDate|验证日期为当前时间或之后|为null有效
|@Past           |Date、Calendar、Instant、LocalDate、LocalDateTime、LocalTime、MonthDay、OffsetDateTime、OffsetTime、Year、YearMonth、ZonedDateTime、HijrahDate、JapaneseDate、MinguoDate、ThaiBuddhistDate|验证日期为当前时间之前|为null有效
|@PastOrPresent  |Date、Calendar、Instant、LocalDate、LocalDateTime、LocalTime、MonthDay、OffsetDateTime、OffsetTime、Year、YearMonth、ZonedDateTime、HijrahDate、JapaneseDate、MinguoDate、ThaiBuddhistDate|验证日期为当前时间或之前|为null有效

5. 数值检查

|注解	        |支持Java类型	                                                        |说明	    |备注
|@Max	        |BigDecimal、BigInteger,byte、short、int、long以及包装类	                |小于或等于	|为null有效
|@Min	        |BigDecimal、BigInteger,byte、short、int、long以及包装类	                |大于或等于	|为null有效
|@DecimalMax	|BigDecimal、BigInteger、CharSequence,byte、short、int、long以及包装类	|小于或等于	|为null有效
|@DecimalMin	|BigDecimal、BigInteger、CharSequence,byte、short、int、long以及包装类	|大于或等于	|为null有效
|@Negative	    |BigDecimal、BigInteger,byte、short、int、long、float、double以及包装类	|负数	    |为null有效,0无效
|@NegativeOrZero|BigDecimal、BigInteger,byte、short、int、long、float、double以及包装类	|负数或零	|为null有效
|@Positive	    |BigDecimal、BigInteger,byte、short、int、long、float、double以及包装类	|正数	    |为null有效,0无效
|@PositiveOrZero|BigDecimal、BigInteger,byte、short、int、long、float、double以及包装类	|正数或零	|为null有效
|@Digits(integer = 3, fraction = 2)|BigDecimal、BigInteger、CharSequence,byte、short、int、long以及包装类|整数位数和小数位数上限|为null有效

6. 其他

|注解	  |支持Java类型	  						|说明						|备注
|@Pattern |CharSequence	  						|匹配指定的正则表达式		    |为null有效
|@Email	  |CharSequence	  						|邮箱地址					|为null有效,默认正则 '.*'
|@Size	  |CharSequence、Collection、Map、Array	|大小范围(length/size>0|为null有效
|@Length  |String								|字符串长度范围				|
|@Range	  |数值类型和String						|指定范围					|
|@URL	  |								 		|URL地址验证					|

7.自定义注解

 - 创建约束注解
 - 实现一个验证器
 - 定义默认的错误信息

@Documented
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Constraint(validatedBy = {MobileValidator.class})
@Retention(RUNTIME)
@Repeatable(Mobile.List.class)
public @interface Mobile {

    /**
     * 错误提示信息,可以写死,也可以填写国际化的key
     */
    String message() default "手机号码不正确";

    Class<?>[] groups() default {};
    
    Class<? extends Payload>[] payload() default {};

    String regexp() default "^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}$";

    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
    @Retention(RUNTIME)
    @Documented
    @interface List {
        Mobile[] value();
    }
}

@Repeatable注解和List定义可以让该注解在同一个位置重复多次,通常是不同的配置(比如不同的分组和消息)
@Constraint(validatedBy = {MobileValidator.class})该注解是指明我们的自定义约束的验证器,那下面就看一下验证器的写法,需要实现javax.validation.ConstraintValidator接口
||message 错误提示信息,可以写死,也可以填写国际化的key
||groups 分组信息,允许指定此约束所属的验证组
||payload 有效负载,可以通过payload来标记一些需要特殊处理的操作

public class MobileValidator implements ConstraintValidator<Mobile, String> {

    /**
     * 手机验证规则
     */
    private Pattern pattern;

    @Override
    public void initialize(Mobile mobile) {
        pattern = Pattern.compile(mobile.regexp());
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }

        return pattern.matcher(value).matches();
    }
}
ConstraintValidator接口定义了在实现中设置的两个类型参数。第一个指定要验证的注解类(如Mobile),第二个指定验证器可以处理的元素类型(如String);initialize()方法可以访问约束注解的属性值;isValid()方法用于验证,返回true表示验证通过

@Mobile String mobile
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
@Target({FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {DateValidator.DateValidatorInner.class})
public @interface DateValidator {

    /**
     * 必须的属性
     * 显示 校验信息
     * 利用 {} 获取 属性值,参考了官方的message编写方式
     *@see org.hibernate.validator 静态资源包里面 message 编写方式
     */
    String message() default "日期格式不匹配{dateFormat}";

    /**
     * 必须的属性
     * 用于分组校验
     */
    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    /**
     * 非必须
     */
    String dateFormat() default "yyyy-MM-dd HH:mm:ss";

    /**
     * 必须实现 ConstraintValidator接口
     */
    class DateValidatorInner implements ConstraintValidator<DateValidator, String> {
        private String dateFormat;

        @Override
        public void initialize(DateValidator constraintAnnotation) {
            this.dateFormat = constraintAnnotation.dateFormat();

        }

        /**
         * 校验逻辑的实现
         * @param value 需要校验的 值
         * @return 布尔值结果
         */
        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            if (value == null) {
                return true;
            }
            if("".equals(value)){
                return true;
            }
            try {
                Date date = DateUtils.parseDate(value, dateFormat);
                return date != null;
            } catch (ParseException e) {
                return false;
            }
        }
    }
}

 @DateValidator(dateFormat = "yyyy-MM-dd")
 private String birthday;

6.配置Validator


@Configuration
public class ValidatorConfig {

    /**
     * 配置验证器
     *
     * @return validator
     */
    @Bean
    public Validator validator() {
        ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
                .configure()
                开启快速校验,默认校验所有参数,false校验全部
                .failFast(true)
                //.addProperty( "hibernate.validator.fail_fast", "true" )
                .buildValidatorFactory();
        return validatorFactory.getValidator();
    }
}

可以通过方法 failFast(true)addProperty("hibernate.validator.fail_fast", "true")设置为快速失败模式,快速失败模式在校验过程中,当遇到第一个不满足条件的参数时就立即返回,不再继续后面参数的校验。否则会一次性校验所有参数,并返回所有不符合要求的错误信息

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值