Как реализовать интернационализацию в методах ErrorResponse?

Добрый день! 

В официальной документации по Spring <a href="https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-ann-rest-exceptions.html#mvc-ann-rest-exceptions-i18n" rel="nofollow">https://docs.spring.io/spring-framework/reference/...</a> указано, что: 

<blockquote>An ErrorResponse exposes message codes for "type", "title", and "detail", as well as message code arguments for the "detail" field. ResponseEntityExceptionHandler resolves these through a MessageSource and updates the corresponding ProblemDetail fields accordingly.</blockquote> 

Не могли бы вы привести пример использования MessageSource для вывода сообщений? Мне не удается настроить правильное отображение сообщений.
  • 14 сентября 2024 г. 10:33
Ответы на вопрос 2
Добрый день!

Для реализации интернационализации (i18n) в методах обработки ошибок (`ErrorResponse`) в Spring вы можете использовать `MessageSource`. Таким образом, вы сможете обеспечить локализацию сообщений об ошибках. Ниже представлен пример, который демонстрирует, как это можно сделать.

### Шаг 1: Настройка MessageSource

1. Создайте файлы сообщений для разных языков, например:
   - `messages.properties` (по умолчанию)
   - `messages_en.properties` (для английского)
   - `messages_ru.properties` (для русского)

Пример содержания `messages.properties`:

```properties
error.not_found=Resource not found
error.internal_server=Internal server error
```

Пример содержания `messages_ru.properties`:

```properties
error.not_found=Ресурс не найден
error.internal_server=Внутренняя ошибка сервера
```

### Шаг 2: Настройка Spring для использования MessageSource

Вы можете Внедрить `MessageSource` в ваш класс конфигурации:

```java
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;

@Configuration
public class AppConfig {

    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("messages");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }
}
```

### Шаг 3: Исполнение ErrorResponse

Теперь вы можете использовать `MessageSource` в вашем обработчике ошибок. Пример показан ниже:

```java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import java.util.Locale;

@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @Autowired
    private MessageSource messageSource;

    @ExceptionHandler(ResourceNotFoundException.class)
    protected ResponseEntity<ErrorResponse> handleResourceNotFound(
            ResourceNotFoundException ex, WebRequest request, Locale locale) {

        String messageTitle = messageSource.getMessage("error.not_found", null, locale);
        String detailMessage = messageSource.getMessage("error.detail", new Object[]{ex.getResourceId()}, locale);

        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setTitle(messageTitle);
        errorResponse.setDetail(detailMessage);
        errorResponse.setStatus(HttpStatus.NOT_FOUND.value());
        
        return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
    }
    
    @ExceptionHandler(Exception.class)
    protected ResponseEntity<ErrorResponse> handleGenericException(
            Exception ex, WebRequest request, Locale locale) {
        
        String messageTitle = messageSource.getMessage("error.internal_server", null, locale);
        
        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setTitle(messageTitle);
        errorResponse.setDetail(ex.getMessage());
        errorResponse.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        
        return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
```

### Шаг 4: Использование локализации

Вы можете передавать желаемую локаль через заголовок запроса или контекст. Например, если вы передаете заголовок `Accept-Language`, Spring автоматически выберет соответствующие сообщения из `MessageSource`.

### Примечания

- Убедитесь, что вы добавили обработку локализации, как описано в [официальной документации Spring](https://docs.spring.io/spring-framework/reference/web.html#mvc-i18n).
- Не забудьте добавить зависимости для таких компонентов, как Spring Web и Spring Context, если они еще не указаны в вашем проекте.

Теперь, следуя этому примеру, вы сможете использовать `MessageSource` для интернационализации сообщений в `ErrorResponse` в вашем приложении на Spring.
public static final String I18_BUNDLE_LOCATION = "language/messages";
    
@Bean
    public ResourceBundleMessageSource resourceBundleMessageSource() {
        final var source = new ResourceBundleMessageSource();
        {
            source.setBasename(I18_BUNDLE_LOCATION);
            source.setDefaultEncoding(StandardCharsets.UTF_8.name());
        }

        return source;
    }

Похожие вопросы