有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步, 认准 https://blog.zysicyj.top
一、创建一个简单的约束
1. 约束注释
1 2 3 4
| public enum CaseMode { UPPER, LOWER; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.RetentionPolicy.RUNTIME; @Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE, TYPE_USE }) @Retention(RUNTIME) @Constraint(validatedBy = CheckCaseValidator.class) @Documented @Repeatable(List.class) public @interface CheckCase { String message() default "{org.hibernate.validator.referenceguide.chapter06.CheckCase." + "message}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; CaseMode value(); @Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE }) @Retention(RUNTIME) @Documented @interface List { CheckCase[] value(); } }
|
1 2 3 4 5 6
| public class Severity { public interface Info extends Payload { } public interface Error extends Payload { } }
|
1 2 3 4 5 6 7 8
| public class ContactDetails { @NotNull(message = "Name is mandatory", payload = Severity.Error.class) private String name; @NotNull(message = "Phone number not specified, but not mandatory", payload = Severity.Info.class) private String phoneNumber; }
|
用法
@Target 定义约束所支持的目标元素类型
@Retention(RUNTIME):指定此类型的注释将在运行时通过反射方式提供
@Constraint(validatedBy = CheckCaseValidator.class):将注释类型标记为约束注释,并指定用于验证元素的验证器
@CheckCase。如果可以在几种数据类型上使用约束,则可以指定几个验证器,每种数据类型一个
@Repeatable(List.class):表示注释可以在同一位置重复多次,通常使用不同的配置
2. 约束验证器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> { private CaseMode caseMode; @Override public void initialize(CheckCase constraintAnnotation) { this.caseMode = constraintAnnotation.value(); } @Override public boolean isValid(String object, ConstraintValidatorContext constraintContext) { if (object == null ) { return true; } if (caseMode == CaseMode.UPPER) { return object.equals(object.toUpperCase() ); } else { return object.equals(object.toLowerCase() ); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> { private CaseMode caseMode; @Override public void initialize(CheckCase constraintAnnotation) { this.caseMode = constraintAnnotation.value(); } @Override public boolean isValid(String object, ConstraintValidatorContext constraintContext) { if (object == null ) { return true; } boolean isValid; if (caseMode == CaseMode.UPPER) { isValid = object.equals(object.toUpperCase() ); } else { isValid = object.equals(object.toLowerCase() ); } if (!isValid) { constraintContext.disableDefaultConstraintViolation(); constraintContext.buildConstraintViolationWithTemplate( "{org.hibernate.validator.referenceguide.chapter06." + "constraintvalidatorcontext.CheckCase.message}" ) .addConstraintViolation(); } return isValid; } }
|
- HibernateConstraintValidator(对原版进行扩展)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class MyFutureValidator implements HibernateConstraintValidator<MyFuture, Instant> { private Clock clock; private boolean orPresent; @Override public void initialize(ConstraintDescriptor<MyFuture> constraintDescriptor, HibernateConstraintValidatorInitializationContext initializationContext) { this.orPresent = constraintDescriptor.getAnnotation().orPresent(); this.clock = initializationContext.getClockProvider().getClock(); } @Override public boolean isValid(Instant instant, ConstraintValidatorContext constraintContext) { return false; } }
|
将有效负载传递给约束验证器
- 在 ValidatorFactory 初始化期间定义约束验证器有效载荷
1 2 3 4 5
| ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class) .configure() .constraintValidatorPayload("US" ) .buildValidatorFactory(); Validator validator = validatorFactory.getValidator();
|
- 使用 Validator 上下文定义约束验证器有效载荷
1 2 3 4 5 6 7 8 9 10 11 12
| HibernateValidatorFactory hibernateValidatorFactory = Validation.byDefaultProvider() .configure() .buildValidatorFactory() .unwrap(HibernateValidatorFactory.class); Validator validator = hibernateValidatorFactory.usingContext() .constraintValidatorPayload("US" ) .getValidator();
validator = hibernateValidatorFactory.usingContext() .constraintValidatorPayload("FR" ) .getValidator();
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class ZipCodeValidator implements ConstraintValidator<ZipCode, String> { public String countryCode; @Override public boolean isValid(String object, ConstraintValidatorContext constraintContext) { if (object == null ) { return true; } boolean isValid = false; String countryCode = constraintContext .unwrap(HibernateConstraintValidatorContext.class) .getConstraintValidatorPayload(String.class); if ("US".equals(countryCode) ) { } else if ("FR".equals(countryCode) ) { } else { } return isValid; } }
|
3. 错误讯息
1
| org.hibernate.validator.referenceguide.chapter06.CheckCase.message = 案例模式必须为 {value}。
|
4. 使用约束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Car { @NotNull private String manufacturer; @NotNull @Size(min = 2, max = 14) @CheckCase(CaseMode.UPPER) private String licensePlate; @Min(2) private int seatCount; public Car(String manufacturer, String licencePlate, int seatCount) { this.manufacturer = manufacturer; this.licensePlate = licencePlate; this.seatCount = seatCount; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| Car car = new Car("Morris", "dd-ab-123", 4 ); Set<ConstraintViolation<Car>> constraintViolations = validator.validate(car); assertEquals(1, constraintViolations.size()); assertEquals( "Case mode must be UPPER.", constraintViolations.iterator().next().getMessage() );
car = new Car("Morris", "DD-AB-123", 4 ); constraintViolations = validator.validate(car); assertEquals(0, constraintViolations.size());
|
二、类级别约束
1 2 3 4 5 6 7 8 9 10
| @Target({ TYPE, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = { ValidPassengerCountValidator.class }) @Documented public @interface ValidPassengerCount { String message() default "{org.hibernate.validator.referenceguide.chapter06.classlevel." + "ValidPassengerCount.message}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class ValidPassengerCountValidator implements ConstraintValidator<ValidPassengerCount, Car> { @Override public void initialize(ValidPassengerCount constraintAnnotation) { } @Override public boolean isValid(Car car, ConstraintValidatorContext context) { if (car == null ) { return true; } return car.getPassengers().size() <= car.getSeatCount(); } }
|
自定义属性路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class ValidPassengerCountValidator implements ConstraintValidator<ValidPassengerCount, Car> { @Override public void initialize(ValidPassengerCount constraintAnnotation) { } @Override public boolean isValid(Car car, ConstraintValidatorContext constraintValidatorContext) { if (car == null ) { return true; } boolean isValid = car.getPassengers().size() <= car.getSeatCount(); if (!isValid) { constraintValidatorContext.disableDefaultConstraintViolation(); constraintValidatorContext .buildConstraintViolationWithTemplate("{my.custom.template}" ) .addPropertyNode("passengers" ).addConstraintViolation(); } return isValid; } }
|
三、交叉级别约束
1 2 3 4 5 6 7 8 9 10
| @Constraint(validatedBy = ConsistentDateParametersValidator.class) @Target({ METHOD, CONSTRUCTOR, ANNOTATION_TYPE }) @Retention(RUNTIME) @Documented public @interface ConsistentDateParameters { String message() default "{org.hibernate.validator.referenceguide.chapter04." + "crossparameter.ConsistentDateParameters.message}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @SupportedValidationTarget(ValidationTarget.PARAMETERS) public class ConsistentDateParametersValidator implements ConstraintValidator<ConsistentDateParameters, Object[]> { @Override public void initialize(ConsistentDateParameters constraintAnnotation) { } @Override public boolean isValid(Object[] value, ConstraintValidatorContext context) { if (value.length != 2 ) { throw new IllegalArgumentException("Illegal method signature" ); } if (value[0] == null || value[1] == null ) { return true; } if (!( value[0] instanceof Date ) || !(value[1] instanceof Date ) ) { throw new IllegalArgumentException( "Illegal method signature, expected two " + "parameters of type Date." ); } return ((Date) value[0] ).before((Date) value[1] ); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Constraint(validatedBy = { ScriptAssertObjectValidator.class, ScriptAssertParametersValidator.class }) @Target({ TYPE, FIELD, PARAMETER, METHOD, CONSTRUCTOR, ANNOTATION_TYPE }) @Retention(RUNTIME) @Documented public @interface ScriptAssert { String message() default "{org.hibernate.validator.referenceguide.chapter04." + "crossparameter.ScriptAssert.message}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; String script(); ConstraintTarget validationAppliesTo() default ConstraintTarget.IMPLICIT; }
|
1 2 3 4 5
| @ScriptAssert(script = "arg1.size() <= arg0", validationAppliesTo = ConstraintTarget.PARAMETERS) public Car buildCar(int seatCount, List<Passenger> passengers) { return null; }
|
四、约束构成
- 创建一个合成约束 @ValidLicensePlate
1 2 3 4 5 6 7 8 9 10 11 12 13
| @NotNull @Size(min = 2, max = 14) @CheckCase(CaseMode.UPPER) @Target({ METHOD, FIELD, ANNOTATION_TYPE, TYPE_USE }) @Retention(RUNTIME) @Constraint(validatedBy = { }) @Documented public @interface ValidLicensePlate { String message() default "{org.hibernate.validator.referenceguide.chapter06." + "constraintcomposition.ValidLicensePlate.message}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; }
|
- 组合约束的应用 ValidLicensePlate
1 2 3 4 5
| public class Car { @ValidLicensePlate private String licensePlate; }
|
- 使用 @ReportAsSingleViolation
1 2 3 4 5 6 7 8 9
| @ReportAsSingleViolation public @interface ValidLicensePlate { String message() default "{org.hibernate.validator.referenceguide.chapter06." + "constraintcomposition.reportassingle.ValidLicensePlate.message}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; } ```ayload() default { }; }
|