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. 🚀

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay