Java Hibernate Validator JSR-303验证

目录

        • 简介
        • 集成
        • 使用
            • 校验对象
            • 校验属性
            • 分组校验
            • 自定义约束
            • 封装
            • 配合Spring使用
          • 注解使用说明

简介

JSR-303是JAVA EE 6中的一项子规范,叫做 Bean Validation,Hibernate Validator是Bean Validation 的参考实现。实际使用就是通过注解来给字段添加约束,然后校验字段是否符合规范,如果不符合就会抛出异常,以此来减少校验数据的代码,并保证拿到的数据都是符合规范的,也可以和Spring框架配合使用

集成

官方文档
https://mvnrepository.com/artifact/org.hibernate/hibernate-validator
https://mvnrepository.com/artifact/javax.validation/validation-api

        <dependency>
            <groupId>org.hibernategroupId>
            <artifactId>hibernate-validatorartifactId>
            <version>6.0.10.Finalversion>
        dependency>
        <dependency>
            <groupId>org.glassfishgroupId>
            <artifactId>javax.elartifactId>
            <version>3.0.1-b09version>
        dependency>
        <dependency>
            <groupId>javax.validationgroupId>
            <artifactId>validation-apiartifactId>
            <version>2.0.1.Finalversion>
        dependency>

使用

校验对象
public class JsrTest {

    @NotNull(message = "id不能为空!")
    @Min(value = 1, message = "Id只能大于等于1")
    Integer id;

    @NotNull(message = "姓名不能为空!")
    String name;

    public void validateParams() {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();//获取一个验证器
        Set<ConstraintViolation<JsrTest>> violationSet = validator.validate(this);//验证数据,获取到错误集合
        Iterator<ConstraintViolation<JsrTest>> iterator = violationSet.iterator();
        if (iterator.hasNext()) {
            String errorMessage = iterator.next().getMessage();//获取到错误信息
            throw new ValidationException(errorMessage);
        }
    }

    public static void main(String args[]) {
        JsrTest req = new JsrTest();
        req.id = 1;
        req.validateParams();
    }

}

像上面那样将在属性上添加注解即可声明约束

校验属性

上面是校验整个对象,也可以单独校验某个字段:

 validator.validateProperty(object, "name");
分组校验
public class JsrTest {

    @NotNull(message = "id不能为空!", groups = {ValidationGroup.class})
    @Min(value = 1, message = "Id只能大于等于1")
    Integer id;

    @NotNull(message = "姓名不能为空!", groups = {ValidationGroup.class})
    String name;

    @DecimalMin(value = "1.1")
    double price;

    int date;

    public static void validateParams(JsrTest jsrTest) {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<JsrTest>> violationSet = validator.validate(jsrTest, ValidationGroup.class);
        Iterator<ConstraintViolation<JsrTest>> iterator = violationSet.iterator();
        if (iterator.hasNext()) {
            String errorMessage = iterator.next().getMessage();
            throw new ValidationException(errorMessage);
        }
    }

    public static void main(String args[]) {
        JsrTest req = new JsrTest();
        validateParams(req);
    }
    
    public interface ValidationGroup {

    }
}

分组校验所指定的calss必须是一个接口,可以指定多个

自定义约束

通常情况下,框架提供的注解已经可以满足正常的验证需求,但是我们也可以自定义注解来满足我们的需求

我们这里的例子是所注释的字符串中不能包含指定字符

@Target(FIELD)      //元注解,定义该注解使用在字段上
@Retention(RUNTIME) //定义注解的生命周期
@Constraint(validatedBy = CustomValidator.class)//指明该注解的校验器
@Documented         //表示该注解会被添加到JavaDoc中
public @interface CustomConstraints {

    String message() default "默认异常message";

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

    Class<? extends Payload>[] payload() default {}; //这个属性可以用来标注错误的严重等级,但是并不被API自身所使用

    String value() default " ";
}
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

/**
 * 需要实现ConstraintValidator接口
 * 泛型的第一个参数是自定义的注解,第二个参数注解所注释的字段的类型
 */
public class CustomValidator implements ConstraintValidator<CustomConstraints, String> {

    private String value;

    /**
     * 初始化调用,拿到注解所指定的value
     *
     * @param constraintAnnotation
     */
    @Override
    public void initialize(CustomConstraints constraintAnnotation) {
        value = constraintAnnotation.value();
    }

    /**
     * @param value   注释的字段的值
     * @param context
     * @return true 通过验证,false 未通过验证
     */
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value != null && value.contains(this.value)) {
            context.disableDefaultConstraintViolation();//禁用默认的消息
            context.buildConstraintViolationWithTemplate("新添加的错误消息").addConstraintViolation();
            return false;
        }
        return true;
    }
}

然后就可以和其他注解一样使用它了

封装

或者是将验证参数的代码提取去出来,单独写一个方法

    public static void validateParams(Object object) {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();//获取一个验证器
        Set<ConstraintViolation<Object>> violationSet = validator.validate(object);//验证数据,获取到错误集合
        Iterator<ConstraintViolation<Object>> iterator = violationSet.iterator();
        if (iterator.hasNext()) {
            String errorMessage = iterator.next().getMessage();//获取到错误信息
            throw new ValidationException(errorMessage);
        }
    }

当然这里也可以不抛出异常,而返回一个boolean值,如何封装看实际需求

配合Spring使用
    @GetMapping("/test")
    public Integer lookCanBuyGoods(@Valid JsrTest req, BindingResult result) throws Exception {
        if (result.hasErrors()) {
            throw new ValidationException(result.getAllErrors().get(0).getDefaultMessage());
        }
        //do something...
        return 1;
    }

@Valid添加这个注解之后就会对参数进行验证,如果在其后没有跟BindingResult,验证不通过就会直接抛出异常,如果添加了BindingResult参数,就不会直接抛出异常,而会把异常信息存储在BindingResult中,供开发者自行处理

如果想要使用分组可以这样

    @GetMapping("/test")
    public Integer test(@Validated (JsrTest.ValidationGroup.class) JsrTest req, BindingResult result) throws Exception {
        if (result.hasErrors()) {
            throw new ValidationException(result.getAllErrors().get(0).getDefaultMessage());
        }
        //do something...
        return 1;
    }

@Validated如果不使用分组其作用和@Valid一致

注解使用说明
Constraint 详细信息
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@PastOrPresent 被注释的元素必须是过去或现在的日期
@Future 被注释的元素必须是一个将来的日期
@FutureOrPresent 被注释的元素必须是将来或现在的日期
@Pattern(value) 被注释的元素必须符合指定的正则表达式
@Digits(integer =, fraction =) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证
@NotBlank 字符串不能是Null还有被Trim的长度要大于0
@NotEmpty 不能为null,且长度大于0
@Negative 被注释的元素必须是负数
@NegativeOrZero 被注释的元素必须是负数或0
@Positive 必须是正数
@PositiveOrZero 必须是正数或0

你可能感兴趣的:(Java)