Перейти к основному содержимому

Интерполяция сообщения Spring Validation

· 4 мин. чтения

1. Введение

Интерполяция сообщений — это процесс, используемый для создания сообщений об ошибках для ограничений проверки Java-бинов . Например, мы можем увидеть сообщения, предоставив нулевое значение для поля, аннотированного аннотацией javax.validation.constraints.NotNull .

В этом руководстве мы узнаем, как использовать интерполяцию сообщений Spring по умолчанию и как создать собственный механизм интерполяции.

Чтобы увидеть примеры других библиотек, предоставляющих ограничения помимо javax.validation , взгляните на Hibernate Validator Specific Constraints . Мы также можем создать пользовательскую аннотацию Spring Validation .

2. Интерполяция сообщений по умолчанию

Прежде чем перейти к фрагментам кода, давайте рассмотрим пример ответа HTTP 400 с сообщением о нарушении ограничения @NotNull по умолчанию :

{
....
"status": 400,
"error": "Bad Request",
"errors": [
{
....
"defaultMessage": "must not be null",
....
}
],
"message": "Validation failed for object='notNullRequest'. Error count: 1",
....
}

Spring извлекает детали сообщения о нарушении ограничений из дескрипторов сообщений. Каждое ограничение определяет свой дескриптор сообщения по умолчанию, используя атрибут сообщения . Но, конечно, мы можем перезаписать его произвольным значением.

В качестве примера мы создадим простой контроллер REST с методом POST:

@RestController
public class RestExample {

@PostMapping("/test-not-null")
public void testNotNull(@Valid @RequestBody NotNullRequest request) {
// ...
}
}

Тело запроса будет сопоставлено с объектом NotNullRequest , который содержит только одну строку String с аннотацией @NotNull :

public class NotNullRequest {

@NotNull(message = "stringValue has to be present")
private String stringValue;

// getters, setters
}

Теперь, когда мы отправляем запрос POST, который не проходит эту проверку, мы увидим наше пользовательское сообщение об ошибке:

{
...
"errors": [
{
...
"defaultMessage": "stringValue has to be present",
...
}
],
...
}

Единственное значение, которое изменяется, — это defaultMessage . Но мы по-прежнему получаем много информации о кодах ошибок, имени объекта, имени поля и т. д. Чтобы ограничить количество отображаемых значений, мы можем реализовать Custom Error Message Handling для REST API .

3. Интерполяция с выражениями сообщений

В Spring мы можем использовать Unified Expression Language для определения наших дескрипторов сообщений . Это позволяет определять сообщения об ошибках на основе условной логики, а также включает расширенные параметры форматирования .

Чтобы понять это более четко, давайте рассмотрим несколько примеров.

В каждой аннотации ограничения мы можем получить доступ к фактическому значению проверяемого поля:

@Size(
min = 5,
max = 14,
message = "The author email '${validatedValue}' must be between {min} and {max} characters long"
)
private String authorEmail;

Наше сообщение об ошибке будет содержать как фактическое значение свойства, так и параметры min и max аннотации @Size :

"defaultMessage": "The author email 'toolongemail@foreach.com' must be between 5 and 14 characters long"

Обратите внимание, что для доступа к внешним переменным мы используем синтаксис ${} , но для доступа к другим свойствам из аннотации проверки мы используем {} .

Также возможно использование тернарного оператора:

@Min(
value = 1,
message = "There must be at least {value} test{value > 1 ? 's' : ''} in the test case"
)
private int testCount;

Spring преобразует тернарный оператор в одно значение в сообщении об ошибке:

"defaultMessage": "There must be at least 2 tests in the test case"

Мы также можем вызывать методы для внешних переменных:

@DecimalMin(
value = "50",
message = "The code coverage ${formatter.format('%1$.2f', validatedValue)} must be higher than {value}%"
)
private double codeCoverage;

Неверный ввод приведет к появлению сообщения об ошибке с отформатированным значением:

"defaultMessage": "The code coverage 44.44 must be higher than 50%"

Как мы видим из этих примеров, некоторые символы, такие как {, }, $ и / , используются в выражениях сообщений, поэтому нам нужно экранировать их символом обратной косой черты, прежде чем использовать их буквально: \{, \}, \$, и \\ .

4. Пользовательская интерполяция сообщений

В некоторых случаях мы хотим реализовать собственный механизм интерполяции сообщений . Для этого мы должны сначала реализовать интерфейс 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);
}
}

В этой простой реализации мы просто меняем сообщение об ошибке на верхний регистр. При этом наше сообщение об ошибке будет выглядеть так:

"defaultMessage": "THE CODE COVERAGE 44.44 MUST BE HIGHER THAN 50%"

Нам также необходимо зарегистрировать наш интерполятор в фабрике javax.validation.Validation :

Validation.byDefaultProvider().configure().messageInterpolator(
new MyMessageInterpolator(
Validation.byDefaultProvider().configure().getDefaultMessageInterpolator())
);

5. Вывод

В этой статье мы узнали, как работает интерполяция сообщений Spring по умолчанию и как создать собственный механизм интерполяции сообщений.

И, как всегда, весь исходный код доступен на GitHub .