Hibernate Validator 讲解(声明Bean与各级别约束)

Hibernate Validator 讲解(声明Bean与各级别约束)

field级别约束

bean校验中的约束是通过Java注解的形式表现出来的(例如,@NotNull是一个非空约束),再细分的话,有4种类型的约束,它们分别是:field级别的约束、property级别的约束、容器元素的约束和类级别的约束。

field级别的约束的例子

package com.lyj.demo.pojo;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import com.lyj.demo.utils.JacksonUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.builder.ToStringBuilder;

import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

/**
 * @author 凌兮
 * @date 2020/9/2 13:44
 * hibernate Validator测试类
 */
@Data
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
@AllArgsConstructor
@NoArgsConstructor
public class ValidatorT {
   

    @NotNull
    private Integer returnOrderId;

    @AssertTrue
    private Boolean isRegistered;

    @NotBlank
    private String goodsName;

    @Override
    public String toString() {
   
        return ToStringBuilder.reflectionToString(this);
//        return JacksonUtil.toJson(this);
    }
}

小结:

当使用field级别的约束的时候,hibernate validator会使用field访问策略来访问需要校验的值,这意味着,校验引擎直接访问实例变量而不是通过调用属性访问方法(getter方法),即使属性访问方法存在也不行。`
`任何访问级别的field都可以使用约束(public private等),但是static的不行。

Property级别约束

本文讲解property级别的约束。如果我们的模型类使用的是标准的Java bean的话,我们也可以使用property级别的约束来替代field级别的约束。

Property级别约束例子

package com.lyj.demo.pojo;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.builder.ToStringBuilder;

import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

/**
 * @author  凌兮
 * @date 2020/9/2 13:44
 * hibernate Validator property级别的约束测试类
 */
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class ValidatorT2 {
   

    private Integer returnOrderId;

    private Boolean isRegistered;

    private String goodsName;

    @NotNull
    public Integer getReturnOrderId() {
   
        return returnOrderId;
    }

    public void setReturnOrderId(Integer returnOrderId) {
   
        this.returnOrderId = returnOrderId;
    }

    @AssertTrue
    public Boolean getRegistered() {
   
        return isRegistered;
    }

    public void setRegistered(Boolean registered) {
   
        isRegistered = registered;
    }

    @NotBlank
    public String getGoodsName() {
   
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
   
        this.goodsName = goodsName;
    }

    @Override
    public String toString() {
   
        return ToStringBuilder.reflectionToString(this);
//        return JacksonUtil.toJson(this);
    }
}

小结

当使用property级别的约束的时候,hibernate validator会使用property访问策略来访问需要校验的值,校验引擎通过getter方法访问要被校验的值。`
`建议在一个模型类中,field级别的约束和property级别的约束不要同时使用,否则会导致一个属性被校验2次。
不建议使用Property级别约束,不方便也不太美观

类级别约束

field级别的约束property级别的约束都是针对单个属性的,而类级别的属性则是针对整个对象的,这在一个对象的多个属性之间具有相关性的情况下是非常有用的。

类级别约束例子

自定义注解

/**
 * @author  凌兮
 * @date 2020/9/2 18:54
 * 类级别约束测试注解
 */
@Target({
   ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {
   PassengerValidor.class})
public @interface ValidPassengerAnnotation {
   

    String message() default "人员超载";

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

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

}

自定义注解校验规则

/**
 * @author  凌兮
 * @date 2020/9/2 19:01
 * 类级别约束校验拦截器校验
 */
public class PassengerValidor implements ConstraintValidator<ValidPassengerAnnotation, ValidatorT3> {
   
    @Override
    public void initialize(ValidPassengerAnnotation constraintAnnotation) {
   

    }

    @Override
    public boolean isValid(ValidatorT3 validatorT3, ConstraintValidatorContext constraintValidatorContext) {
   
        if (Objects.isNull(validatorT3)) {
   
            return true;
        }

        return validatorT3.getSeatNum() <= validatorT3.getStudentList().size();

    }
}

pojo

/**
 * @author  凌兮
 * @date 2020/9/2 13:44
 * hibernate Validator 类级别约束测试类
 */
@Data
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
@AllArgsConstructor
@NoArgsConstructor
@ValidPassengerAnnotation
public class ValidatorT3 {
   

    private Integer returnOrderId;

    private Boolean isRegistered;

    private String goodsName;

    private Integer seatNum;

    private List<Student> studentList;

    @Override
    public String toString() {
   
        return ToStringBuilder.reflectionToString(this);
//        return JacksonUtil.toJson(this);
    }
}

小结

通过上面案例,我们只要了解到如果一个对象的多个属性之间有约束关系,那么我们可以使用class级别的来校验就行了,有关自定义注解和拦截器使用可以自行百度。

继承之Property级别约束

继承之Property级别约束例子

当一个类实现了某接口或者继承了某类的时候,父类型的约束将会被子类型继承。

父类:

package com.lyj.demo.pojo;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.builder.ToStringBuilder;

import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

/**
 * @author  凌兮
 * @date 2020/9/2 13:44
 * hibernate Validator 继承之Property级别约束测试类
 */
@Data
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
@AllArgsConstructor
@NoArgsConstructor
public class ValidatorT4 {
   

    private Integer returnOrderId;

    private Boolean isRegistered;

    private String goodsName;

    @NotBlank(message = "制造商不能为空")
    private String manufacture;


    private Integer seatNum;

    /**
     * 对于父类继承子类并且属性相同,只能覆盖父类的属性,父类的属性会被隐藏,但父类的方法
     * 不会被隐藏,只会被覆盖,所以对于父类和子类的属性相同的注解校验,
     * 子类要覆盖父类的属性方法,并且不能使用@Data自动生成的,否则失效
     *
     * @return
     */
    @Min(value = 2, message = "人数不能小于2")
    public Integer getSeatNum() {
   
        return seatNum;
    }

    public void setSeatNum(Integer seatNum) {
   
        this.seatNum = seatNum;
    }

    @Override
    public String toString() {
   
        return ToStringBuilder.reflectionToString(this);
//        return JacksonUtil.toJson(this);
    }
}

子类:

package com.lyj.demo.pojo;

import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.builder.ToStringBuilder;

import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

/**
 * @author  凌兮
 * @date 2020/9/2 13:44
 * hibernate Validator 继承之Property级别约束测试类
 */
@Data
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
@AllArgsConstructor
@NoArgsConstructor
//@EqualsAndHashCode(callSuper = true) //继承父类
public class ValidatorT5 extends ValidatorT4 {
   

    private Integer orderGoodsId;

    private Boolean isCreated;

    @NotBlank(message = "租赁站不能为空")
    private String relationStation;


    private Integer seatNum;

    /**
     * 对于父类继承子类并且属性相同,只能覆盖父类的属性,父类的属性会被隐藏,但父类的方法
     * 不会被隐藏,只会被覆盖,所以对于父类和子类的属性相同的注解校验,
     *子类要覆盖父类的属性方法,并且不能使用@Data自动生成的,否则失效
     * 并且父类和子类相同属性的注解校验可以共同起作用。
     * 尽管这里添加最小值校验,但和父类的最小值校验一起生效,当小于0时,使用子类报错,当大于0小于2时使用父类的报错
     * @return
     */
    @Max(value = 5, message = "人数不能大于5")
    @Min(value = 0, message = "人数不能小于0")
    @Override
    public Integer getSeatNum() {
   
        return seatNum;
    }

    @Override
    public void setSeatNum(Integer seatNum) {
   
        this.seatNum = seatNum;
    }

    @Override
    public String toString() {
   
        return ToStringBuilder.reflectionToString(this);
//        return JacksonUtil.toJson(this);
    }
}

测试方法;

@RequestMapping(value = "/HOME/ValidTest4", method = RequestMethod.POST)
@ApiOperation(value = "Validator 继承级别约束测试", notes = "Hibernate Validator测试")
public BaseResponse<Void> Validator4Test() {
   
    ValidatorT5 validatorT5 = new ValidatorT5();
    // 设置违反了来自父类的约束
    validatorT5.setManufacture(null);
    validatorT5.setRelationStation(null);
    // 父类和子类的约束可以累加
    validatorT5.setSeatNum(1);
    // 获取Validator工厂接口方法
    ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
    Validator validator = validatorFactory.getValidator();
    Set<ConstraintViolation<ValidatorT5>> validate = validator.validate(validatorT5);
    logger.info("
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凌兮~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值