DEV Community

Uiratan Cavalcante
Uiratan Cavalcante

Posted on

Personalização de Erros com Internacionalização no Spring Boot

1️⃣ Passo: Tratando erros de validação simples

Objetivo: Tratar erros de validação e retornar uma resposta personalizada no formato JSON.

  1. Crie o @RestControllerAdvice para tratar exceções de validação.

Exemplo:

   @RestControllerAdvice
   public class GlobalExceptionHandler {

       @ExceptionHandler(MethodArgumentNotValidException.class)
       @ResponseStatus(HttpStatus.BAD_REQUEST)
       public ErrorResponse handleValidationException(MethodArgumentNotValidException ex) {
           List<FieldErrorResponse> fieldErrors = ex.getBindingResult().getFieldErrors()
               .stream()
               .map(error -> new FieldErrorResponse(error.getField(), error.getDefaultMessage()))
               .collect(Collectors.toList());

           return new ErrorResponse(List.of(), fieldErrors, fieldErrors.size());
       }
   }
Enter fullscreen mode Exit fullscreen mode
  1. Crie a classe ErrorResponse e FieldErrorResponse.

Exemplo:

   public record ErrorResponse(
       List<String> globalErrorMessages,
       List<FieldErrorResponse> errors,
       int numberOfErrors
   ) {}

   public record FieldErrorResponse(String field, String message) {}
Enter fullscreen mode Exit fullscreen mode
  1. Resultado de erro no formato JSON:
   {
     "globalErrorMessages": [],
     "errors": [
       {
         "field": "email",
         "message": "must not be blank"
       }
     ],
     "numberOfErrors": 1
   }
Enter fullscreen mode Exit fullscreen mode

2️⃣ Passo: Adicionando Mensagens de Erro com MessageSource (Internacionalização)

Objetivo: Configurar internacionalização e personalizar as mensagens de erro.

  1. Crie o arquivo de mensagens messages.properties.

Exemplo (src/main/resources/messages.properties):

   error.notblank = O campo {0} não pode estar em branco.
   error.invalid = O valor informado para {0} é inválido.
   error.internal = Ocorreu um erro interno. Tente novamente mais tarde.
Enter fullscreen mode Exit fullscreen mode
  1. Configure o MessageSource no Spring.

Criação da classe MessageSourceConfig:

   @Configuration
   public class MessageSourceConfig {

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

       @Bean
       public LocaleResolver localeResolver() {
           SessionLocaleResolver localeResolver = new SessionLocaleResolver();
           localeResolver.setDefaultLocale(Locale.forLanguageTag("pt-BR"));
           return localeResolver;
       }

       @Bean
       public LocaleChangeInterceptor localeChangeInterceptor() {
           LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
           localeChangeInterceptor.setParamName("lang");
           return localeChangeInterceptor;
       }
   }
Enter fullscreen mode Exit fullscreen mode
  1. Uso do MessageSource no @RestControllerAdvice para mensagens de erro personalizadas.

Modifique o código do @RestControllerAdvice para usar o MessageSource:

   @RestControllerAdvice
   public class GlobalExceptionHandler {

       private final MessageSource messageSource;

       public GlobalExceptionHandler(MessageSource messageSource) {
           this.messageSource = messageSource;
       }

       @ExceptionHandler(MethodArgumentNotValidException.class)
       @ResponseStatus(HttpStatus.BAD_REQUEST)
       public ErrorResponse handleValidationException(MethodArgumentNotValidException ex, Locale locale) {
           List<FieldErrorResponse> fieldErrors = ex.getBindingResult().getFieldErrors()
               .stream()
               .map(error -> new FieldErrorResponse(
                   error.getField(),
                   messageSource.getMessage(error.getDefaultMessage(), new Object[]{error.getField()}, locale)
               ))
               .collect(Collectors.toList());

           return new ErrorResponse(List.of(), fieldErrors, fieldErrors.size());
       }
   }
Enter fullscreen mode Exit fullscreen mode
  1. Resultado de erro internacionalizado em português (pt):
   {
     "globalErrorMessages": [],
     "errors": [
       {
         "field": "email",
         "message": "O campo email não pode estar em branco."
       }
     ],
     "numberOfErrors": 1
   }
Enter fullscreen mode Exit fullscreen mode

3️⃣ Passo: Tratando Exceções Genéricas com @ExceptionHandler(Exception.class)

Objetivo: Capturar qualquer exceção inesperada e retornar uma resposta personalizada.

  1. Adicione o tratamento de exceções genéricas para capturar erros não esperados.

Exemplo:

   @RestControllerAdvice
   public class GlobalExceptionHandler {

       private final MessageSource messageSource;

       public GlobalExceptionHandler(MessageSource messageSource) {
           this.messageSource = messageSource;
       }

       @ExceptionHandler(MethodArgumentNotValidException.class)
       @ResponseStatus(HttpStatus.BAD_REQUEST)
       public ErrorResponse handleValidationException(MethodArgumentNotValidException ex, Locale locale) {
           List<FieldErrorResponse> fieldErrors = ex.getBindingResult().getFieldErrors()
               .stream()
               .map(error -> new FieldErrorResponse(
                   error.getField(),
                   messageSource.getMessage(error.getDefaultMessage(), new Object[]{error.getField()}, locale)
               ))
               .collect(Collectors.toList());

           return new ErrorResponse(List.of(), fieldErrors, fieldErrors.size());
       }

       @ExceptionHandler(Exception.class)
       @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
       public ErrorResponse handleGenericException(Exception ex) {
           List<String> globalErrors = List.of("Ocorreu um erro inesperado. Contate o suporte.");
           return new ErrorResponse(globalErrors, List.of(), 1);
       }
   }
Enter fullscreen mode Exit fullscreen mode
  1. Resultado de erro genérico (quando ocorre uma exceção inesperada):
   {
     "globalErrorMessages": [
       "Ocorreu um erro inesperado. Contate o suporte."
     ],
     "errors": [],
     "numberOfErrors": 1
   }
Enter fullscreen mode Exit fullscreen mode

4️⃣ Passo: Permitir a Troca de Idioma com Parâmetro na URL

Objetivo: Permitir que o idioma da aplicação seja alterado via parâmetro na URL.

  1. Adicione o LocaleResolver e LocaleChangeInterceptor para permitir a troca de idioma.

Já configurado na classe MessageSourceConfig:

   @Bean
   public LocaleResolver localeResolver() {
       SessionLocaleResolver localeResolver = new SessionLocaleResolver();
       localeResolver.setDefaultLocale(Locale.forLanguageTag("pt-BR"));
       return localeResolver;
   }

   @Bean
   public LocaleChangeInterceptor localeChangeInterceptor() {
       LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
       localeChangeInterceptor.setParamName("lang");
       return localeChangeInterceptor;
   }
Enter fullscreen mode Exit fullscreen mode
  1. Testar a troca de idioma na URL:
    • Requisição com idioma português: GET /minha-rota?lang=pt
    • Requisição com idioma inglês: GET /minha-rota?lang=en

📌 Conclusão:

Agora você tem uma aplicação que:

  1. Captura erros de validação e os retorna no formato JSON personalizado.
  2. Personaliza mensagens de erro usando internacionalização (MessageSource).
  3. Captura exceções genéricas e retorna uma resposta consistente para erros inesperados.
  4. Permite trocar o idioma da aplicação dinamicamente via parâmetro na URL.

Esses passos podem ser expandidos conforme a necessidade de sua aplicação, mas com esses fundamentos, você já tem uma base sólida para tratar erros de maneira organizada, escalável e amigável ao usuário. 🚀

Top comments (0)