13.2. 验证约束
13.2.1. 关于验证约束 复制链接链接已复制到粘贴板!
验证约束应用到 Java 元素,如字段、属性或 bean。约束通常具有一组用于设置限值的属性。有预定义的限制,可以创建自定义限制。每个约束都以注释的形式表示。
Hibernate 验证器的内置验证限制如下:Hibernate 验证器约束。
13.2.2. Hibernate 验证器约束 复制链接链接已复制到粘贴板!
如果适用,应用程序级别的限制会导致创建数据库级别限制,下表中的 Hibernate 元数据影响 列中进行了描述。
Java 特定的验证约束
下表包含 Java 规范中定义的验证约束,包含在 javax.validation.constraints 软件包中。
| 注解 | 属性类型 | 运行时检查 | Hibernate 元数据影响 |
|---|---|---|---|
| @AssertFalse | 布尔值 | 检查方法是否评估为 false。用于以代码而不是注释表示的约束。 | none. |
| @AssertTrue | 布尔值 | 检查方法是否评估为 true。用于以代码而不是注释表示的约束。 | none. |
| @Digits(integerDigits=1) | 数字的数字或字符串表示 |
检查该属性是否为具有最多 | 定义列精度和规模. |
| @Future | 日期或日历 | 检查日期是否在将来。 | none. |
| @Max(value=) | 数字的数字或字符串表示 | 检查值是否小于或等于 max。 | 在列中添加检查限制。 |
| @Min(value=) | 数字的数字或字符串表示 | 检查值是否大于或等于 Min。 | 在列中添加检查限制。 |
| @NotNull | 检查值是否不为空。 | 列不为空. | |
| @Past | 日期或日历 | 检查日期是否过去。 | 在列中添加检查限制。 |
| @Pattern(regexp="regexp", flag=) or @Patterns( {@Pattern(…)} ) | 字符串 |
检查 属性是否与给定匹配标记的正则表达式匹配。请参阅 | none. |
| @Size(min=, max=) | 数组、集合、映射 | 检查元素大小是否介于 min 和 max 之间,两个值都包含。 | none. |
| @Valid | 对象 | 对关联的对象递归执行验证。如果对象是 Collection 或数组,则元素会递归验证。如果对象是 Map,则值元素会递归验证。 | none. |
参数 @Valid 是 Jakarta Bean Validation 规范的一部分,即使它位于 javax.validation.constraints 软件包中。
Hibernate 验证器特定的验证约束
下表包含特定于供应商的验证约束,它们是 org.hibernate.validator.constraints 软件包的一部分。
| 注解 | 属性类型 | 运行时检查 | Hibernate 元数据影响 |
|---|---|---|---|
| @Length(min=, max=) | 字符串 | 检查字符串长度是否与范围匹配。 | 列长度将设置为最大值。 |
| @CreditCardNumber | 字符串 | 检查字符串是否为格式良好的信用卡号码,并派生了 Luhn 算法。 | none. |
| @EAN | 字符串 | 检查字符串是否为格式正确的 EAN 或 UPC-A 代码。 | none. |
| | 字符串 | 检查字符串是否符合电子邮件地址规范。 | none. |
| @NotEmpty | 检查字符串是否不为空或空。检查连接是否不为空或为空。 | 列对于字符串不是空的。 | |
| @Range(min=, max=) | 数字的数字或字符串表示 | 检查值是否介于 min 和 max 之间,两个值都包含。 | 在列中添加检查限制。 |
13.2.3. 使用 Jakarta Bean 验证自定义约束 复制链接链接已复制到粘贴板!
Jakarta Bean Validation API 定义一组标准约束注释,如 @NotNull、@Size 等。但是,如果这些预定义的限制不够,您可以轻松创建针对特定验证要求量身定制的自定义限制。
创建 Jakarta Bean Validation 自定义约束要求您 创建一个约束注解 并实施约束验证器。以下缩写的代码示例取自 JBoss EAP 附带的 bean-validation-custom-constraint 快速入门:看到快速入门的完整工作示例。
13.2.3.1. 创建约束注解 复制链接链接已复制到粘贴板!
以下示例显示了使用类 AddressValidator 中定义的一组自定义约束来验证实体 Person 的 personAddress 字段。
创建实体
Person。示例:
PersonClasspackage org.jboss.as.quickstarts.bean_validation_custom_constraint; @Entity @Table(name = "person") public class Person implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue @Column(name = "person_id") private Long personId; @NotNull @Size(min = 4) private String firstName; @NotNull @Size(min = 4) private String lastName; // Custom Constraint @Address for bean validation @NotNull @Address @OneToOne(mappedBy = "person", cascade = CascadeType.ALL) private PersonAddress personAddress; public Person() { } public Person(String firstName, String lastName, PersonAddress address) { this.firstName = firstName; this.lastName = lastName; this.personAddress = address; } /* getters and setters omitted for brevity*/ }创建约束验证器文件。
示例:
地址接口package org.jboss.as.quickstarts.bean_validation_custom_constraint; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; // Linking the AddressValidator class with @Address annotation. @Constraint(validatedBy = { AddressValidator.class }) // This constraint annotation can be used only on fields and method parameters. @Target({ ElementType.FIELD, ElementType.PARAMETER }) @Retention(value = RetentionPolicy.RUNTIME) @Documented public @interface Address { // The message to return when the instance of MyAddress fails the validation. String message() default "Address Fields must not be null/empty and obey character limit constraints"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }示例:
PersonAddress类package org.jboss.as.quickstarts.bean_validation_custom_constraint; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table; @Entity @Table(name = "person_address") public class PersonAddress implements Serializable { private static final long serialVersionUID = 1L; @Id @Column(name = "person_id", unique = true, nullable = false) @GeneratedValue(strategy = GenerationType.SEQUENCE) private Long personId; private String streetAddress; private String locality; private String city; private String state; private String country; private String pinCode; @OneToOne @PrimaryKeyJoinColumn private Person person; public PersonAddress() { } public PersonAddress(String streetAddress, String locality, String city, String state, String country, String pinCode) { this.streetAddress = streetAddress; this.locality = locality; this.city = city; this.state = state; this.country = country; this.pinCode = pinCode; } /* getters and setters omitted for brevity*/ }
13.2.3.2. 实施约束验证器 复制链接链接已复制到粘贴板!
在定义了注释后,您需要创建一个能够使用 @Address 注释验证元素的约束验证器。要做到这一点,实施接口 ConstraintValidator,如下所示:
示例: 地址验证器 类
package org.jboss.as.quickstarts.bean_validation_custom_constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.jboss.as.quickstarts.bean_validation_custom_constraint.PersonAddress;
public class AddressValidator implements ConstraintValidator<Address, PersonAddress> {
public void initialize(Address constraintAnnotation) {
}
/**
* 1. A null address is handled by the @NotNull constraint on the @Address.
* 2. The address should have all the data values specified.
* 3. Pin code in the address should be of at least 6 characters.
* 4. The country in the address should be of at least 4 characters.
*/
public boolean isValid(PersonAddress value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
if (value.getCity() == null || value.getCountry() == null || value.getLocality() == null
|| value.getPinCode() == null || value.getState() == null || value.getStreetAddress() == null) {
return false;
}
if (value.getCity().isEmpty()
|| value.getCountry().isEmpty() || value.getLocality().isEmpty()
|| value.getPinCode().isEmpty() || value.getState().isEmpty() || value.getStreetAddress().isEmpty()) {
return false;
}
if (value.getPinCode().length() < 6) {
return false;
}
if (value.getCountry().length() < 4) {
return false;
}
return true;
}
}