Hibernate中ParameterMessageInterpolator简介
1. 概述
Java JSR 380 的特性之一是在使用参数插入验证消息时允许表达式。
当我们使用 Hibernate Validator 时,**我们需要将 Java JSR 341 的统一实现之一作为依赖添加到我们的项目中。**JSR 341 也称为表达式语言 API。
但是,如果我们不需要根据我们的用例支持解析表达式,那么添加一个额外的库可能会很麻烦。
在这个简短的教程中,我们将了解如何在 Hibernate Validator中配置ParameterMessageInterpolator 。
2. MessageInterpolator
除了验证 Java bean 的基础知识 之外,Bean Validation API 的MessageInterpolator是一种抽象,它为我们提供了一种执行简单插值的方法,而无需解析表达式。
此外,*Hibernate Validator 提供了一个基于非表达式的*ParameterMessageInterpolator,因此我们不需要任何额外的库来配置它。
3. 设置自定义消息插值器
要移除表达式语言依赖,我们可以使用自定义消息插值器并在不支持表达式的情况下配置 Hibernate Validator。 让我们展示一些设置自定义消息插值器的便捷方法。在我们的案例中,我们将使用内置的ParameterMessageInterpolator。
3.1. 配置ValidatorFactory
设置自定义消息插值器的一种方法是在引导时配置ValidatorFactory。
因此,我们可以使用ParameterMessageInterpolator构建一个ValidatorFactory实例:
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.messageInterpolator(new ParameterMessageInterpolator())
.buildValidatorFactory();
3.2. 配置Validator
同样,我们可以在初始化Validator实例时设置ParameterMessageInterpolator:
Validator validator = validatorFactory.usingContext()
.messageInterpolator(new ParameterMessageInterpolator())
.getValidator();
4. 执行验证
要了解ParameterMessageInterpolator是如何工作的,我们需要一个带有一些 JSR 380 注释的示例 Java bean。
4.1. 示例 Java Bean
让我们定义我们的示例 Java bean Person:
public class Person {
@Size(min = 10, max = 100, message = "Name should be between {min} and {max} characters")
private String name;
@Min(value = 18, message = "Age should not be less than {value}")
private int age;
@Email(message = "Email address should be in a correct format: ${validatedValue}")
private String email;
// standard getters and setters
}
4.2. 测试消息参数
当然,要执行我们的验证,我们应该使用从 ValidatorFactory 访问的Validator实例,我们之前已经配置了该实例。
所以,我们需要访问我们的Validator:
Validator validator = validatorFactory.getValidator();
之后,我们可以为name字段编写测试方法:
@Test
public void givenNameLengthLessThanMin_whenValidate_thenValidationFails() {
Person person = new Person();
person.setName("John Doe");
person.setAge(18);
Set<ConstraintViolation<Person>> violations = validator.validate(person);
assertEquals(1, violations.size());
ConstraintViolation<Person> violation = violations.iterator().next();
assertEquals("Name should be between 10 and 100 characters", violation.getMessage());
}
验证消息正确插入了*{min}和{max}*变量:
Name should be between 10 and 100 characters
接下来,让我们为age字段编写一个类似的测试:
@Test
public void givenAgeIsLessThanMin_whenValidate_thenValidationFails() {
Person person = new Person();
person.setName("John Stephaner Doe");
person.setAge(16);
Set<ConstraintViolation<Person>> violations = validator.validate(person);
assertEquals(1, violations.size());
ConstraintViolation<Person> violation = violations.iterator().next();
assertEquals("Age should not be less than 18", violation.getMessage());
}
同样,验证消息按照我们的预期使用变量*{value}*正确插入:
Age should not be less than 18
4.3. 测试表达式
要查看ParameterMessageInterpolator如何处理表达式,让我们为email字段编写另一个包含简单*${validatedValue}*表达式的测试:
@Test
public void givenEmailIsMalformed_whenValidate_thenValidationFails() {
Person person = new Person();
person.setName("John Stephaner Doe");
person.setAge(18);
person.setEmail("johndoe.dev");
Set<ConstraintViolation<Person>> violations = validator.validate(person);
assertEquals(1, violations.size());
ConstraintViolation<Person> violation = violations.iterator().next();
assertEquals("Email address should be in a correct format: ${validatedValue}", violation.getMessage());
}
这一次,表达式*${validatedValue}*没有被插值。
*ParameterMessageInterpolator仅支持参数的插值,不解析使用$*表示法的表达式。**相反,它只是简单地返回它们未插值。