1. Introduction
1.绪论
Message interpolation is the process used for creating error messages for Java bean validation constraints. For example, we can see the messages by providing a null value for a field annotated with the javax.validation.constraints.NotNull annotation.
消息插值是用于为Java Bean验证约束创建错误消息的过程。例如,我们可以通过为一个用javax.validation.constraints.NotNull注解的字段提供一个null值来查看这些消息。
In this tutorial, we’ll learn how to use the default Spring message interpolation and how to create our own interpolation mechanism.
在本教程中,我们将学习如何使用默认的Spring消息插值以及如何创建我们自己的插值机制。
To see examples of other libraries providing constraints besides javax.validation, take a look at Hibernate Validator Specific Constraints. We can also create a custom Spring Validation annotation.
要查看除javax.validation之外的其他库提供约束的例子,请看Hibernate Validator Specific Constraints。我们还可以创建一个custom Spring Validation注解。
2. Default Message Interpolation
2.默认的信息插值
Before getting into code snippets, let’s consider an example of an HTTP 400 response with a default @NotNull constraint violation message:
在进入代码片段之前,让我们考虑一个带有默认@NotNull约束条件违反信息的HTTP 400响应的例子。
{
....
"status": 400,
"error": "Bad Request",
"errors": [
{
....
"defaultMessage": "must not be null",
....
}
],
"message": "Validation failed for object='notNullRequest'. Error count: 1",
....
}
Spring retrieves the constraint violation message details from message descriptors. Each constraint defines its default message descriptor using the message attribute. But, of course, we can overwrite it with a custom value.
Spring从消息描述符中检索约束的违规消息细节。每个约束都使用message属性定义了其默认的消息描述符。但是,当然,我们可以用一个自定义的值来覆盖它。
As an example, we’ll create a simple REST controller with a POST method:
作为一个例子,我们将创建一个具有POST方法的简单REST控制器。
@RestController
public class RestExample {
@PostMapping("/test-not-null")
public void testNotNull(@Valid @RequestBody NotNullRequest request) {
// ...
}
}
The request body will be mapped to the NotNullRequest object, which has just one String filed annotated with @NotNull:
请求主体将被映射到NotNullRequest对象,它只有一个String文件,并注有@NotNull。
public class NotNullRequest {
@NotNull(message = "stringValue has to be present")
private String stringValue;
// getters, setters
}
Now, when we send in a POST request that fails this validation check, we will see our custom error message:
现在,当我们发送的POST请求没有通过这个验证检查时,我们将看到我们自定义的错误信息。
{
...
"errors": [
{
...
"defaultMessage": "stringValue has to be present",
...
}
],
...
}
The only value that changes is defaultMessage. But we still get a lot of information about error codes, object name, field name, etc. To limit the number of displayed values, we can implement Custom Error Message Handling for REST API.
唯一改变的值是defaultMessage。但是我们仍然可以得到很多关于错误代码、对象名称、字段名称等信息。为了限制显示值的数量,我们可以实现Custom Error Message Handling for REST API。
3. Interpolation with Message Expressions
3.用信息表达式进行插值
In Spring, we can use the Unified Expression Language to define our message descriptors. This allows defining error messages based on conditional logic and also enables advanced formatting options.
在Spring中,我们可以使用统一表达式语言来定义我们的消息描述符。这允许根据条件逻辑定义错误信息,也可以实现高级格式化选项。
To understand it more clearly, let’s look at a few examples.
为了更清楚地了解它,让我们看几个例子。
In every constraint annotation, we can access the actual value of a field that’s being validated:
在每个约束注解中,我们可以访问被验证的字段的实际值。
@Size(
min = 5,
max = 14,
message = "The author email '${validatedValue}' must be between {min} and {max} characters long"
)
private String authorEmail;
Our error message will contain both the actual value of the property and min and max parameters of the @Size annotation:
我们的错误信息将包含属性的实际值和min和max参数的@Size注释。
"defaultMessage": "The author email 'toolongemail@baeldung.com' must be between 5 and 14 characters long"
Notice that for accessing external variables, we use ${} syntax, but for accessing other properties from the validation annotation, we use {}.
注意,对于访问外部变量,我们使用${}语法,但对于访问验证注解中的其他属性,我们使用{}。
Using the ternary operator is also possible:
使用三元运算符也是可以的。
@Min(
value = 1,
message = "There must be at least {value} test{value > 1 ? 's' : ''} in the test case"
)
private int testCount;
Spring will convert the ternary operator to a single value in the error message:
在错误信息中,Spring将把三元运算符转换为单值。
"defaultMessage": "There must be at least 2 tests in the test case"
We can also call methods on external variables:
我们也可以在外部变量上调用方法。
@DecimalMin(
value = "50",
message = "The code coverage ${formatter.format('%1$.2f', validatedValue)} must be higher than {value}%"
)
private double codeCoverage;
Invalid input will produce an error message with the formatted value:
无效的输入将产生一个带有格式化值的错误信息。
"defaultMessage": "The code coverage 44.44 must be higher than 50%"
As we can see from these examples, some characters such as {, }, $, and / are used in message expressions, so we need to escape them with a backslash character before using them literally: \{, \}, \$, and \\.
从这些例子中我们可以看到,一些字符如{, }, $,和/在消息表达中使用,所以我们需要在使用它们的字面意思之前用反斜杠字符转义。\{, \}, \$,和\。
4. Custom Message Interpolation
4.自定义信息插值
In some cases, we want to implement a custom message interpolation engine. To do so, we must first implement the javax.validation.MessageInterpolation interface:
在某些情况下,我们想实现一个自定义的消息插值引擎。要做到这一点,我们必须首先实现javax.validation.MessageInterpolation接口。
public class MyMessageInterpolator implements MessageInterpolator {
private final MessageInterpolator defaultInterpolator;
public MyMessageInterpolator(MessageInterpolator interpolator) {
this.defaultInterpolator = interpolator;
}
@Override
public String interpolate(String messageTemplate, Context context) {
messageTemplate = messageTemplate.toUpperCase();
return defaultInterpolator.interpolate(messageTemplate, context);
}
@Override
public String interpolate(String messageTemplate, Context context, Locale locale) {
messageTemplate = messageTemplate.toUpperCase();
return defaultInterpolator.interpolate(messageTemplate, context, locale);
}
}
In this simple implementation, we’re just changing the error message to upper-case. By doing so, our error message will look like:
在这个简单的实现中,我们只是将错误信息改为大写字母。通过这样做,我们的错误信息将看起来像。
"defaultMessage": "THE CODE COVERAGE 44.44 MUST BE HIGHER THAN 50%"
We also need to register our interpolator in the javax.validation.Validation factory:
我们还需要在javax.validation.Validation工厂中注册我们的插值器。
Validation.byDefaultProvider().configure().messageInterpolator(
new MyMessageInterpolator(
Validation.byDefaultProvider().configure().getDefaultMessageInterpolator())
);
5. Conclusion
5.总结
In this article, we’ve learned how default Spring message interpolation works and how to create a custom message interpolation engine.
在这篇文章中,我们已经了解了默认的Spring消息插值是如何工作的,以及如何创建一个自定义的消息插值引擎。
And, as always, all source code is available over on GitHub.
而且,像往常一样,所有的源代码都可以在GitHub上找到。