DEV Community

Wesley Egberto
Wesley Egberto

Posted on • Updated on

Spring - Exception Handler

Para começar, certifique que tem a dependência no seu POM ou Gradle.

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Tratamento Padrão

O tratamento de erro padrão do Spring oferece uma forma out-of-the-box que responde dependendo do Content-type.

  • Caso o Content-Type seja text/html o tratamento de erro irá encaminhar o request para uma página de erro White label error page. Caso você adicione um mapping específico para "/error" então o Spring utilizará esse cara ao invés do White label error page.
  • Caso o Cotent-type seja JSON o tratamento de erro retornará um objeto com as seguintes propriedades: error, message, path, status timestamp.

A página de erro pode ser desabilitada ao adicionar a linha abaixo no seu .properties.

server.error.whitelabel.enabled=false

Tratamento Customizado

Spring fornece uma maneira bem simples e limpa que nos permite tratar exceptions que ocorrem durante a execução de um método do nosso controller MVC/REST. Podemos tratar e retornar um JSON ou encaminhar para uma página especifica de erro.

Usando @ResponseStatus

A primeira forma nos permite tratar apenas o retorno do nosso controller. Na nossa exception adicionamos a anotação @ResponseStatus que permite customizar o HTTP status e o header reason do nosso response. O response ainda será retornado utilizando o tratamento padrão (error page ou JSON padrão) caso não tenha sido definido uma págian ou um handler.

@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "We can't handle your request =(")
public class CustomException extends RuntimeException {
}
@RestController
@RequestMapping("/api")
class HelloController {
   @GetMapping("custom")
   public String customResponseFailure() {
      throw new CustomException();
   }
}

Quando uma exception do tipo CustomException for lançada o tratamento padrão de erro do Spring entrará em ação mas utilizará o nosso HTTP status e adicionará o header reason no response.

Usando @ExceptionHandler

A segunda forma mais interessante é criar  um método para tratar exceptions específicas. Esta forma nos permite cria um método para tratar a exception adequadamente e então encaminhar para uma página específica ou retornar uma entidade customizada.

Se anotarmos um método de uma controller então todos as exceptions daquela controller que não tenham sejam anotadas com @ResponseStatus serão tratadas por ela mas caso queiramos criar um handler para todas as controllers precisamos criar  um Advice.

Temos dois tipos de Advice: ControllerAdviceRestControllerAdvice. O ControllerAdvice segue a semântica do @Controller, então no fim do tratamento ele redireciona para a view definida. O RestControllerAdvice segue o @RestController, então retorna seu objeto serializado direto no response.

Controller com @ExceptionHandler

@Controller
@RequestMapping("/web")
public class PageController {
   @GetMapping("customerrorpage")
   public String customErrorPage() {
      throw new NumberFormatException("We can't format your number");
   }

   @ExceptionHandler(NumberFormatException.class)
   public ModelAndView handleNumberFormatException(NumberFormatException nfex) {
      ModelAndView model = new ModelAndView("custom_error");
      model.addObject("errorMessage", nfex.getMessage());
      return model;
   }
}

Classe com ControllerAdvice e RestControllerAdvice

@ControllerAdvice
public class CustomPageExceptionHandler {
   @ExceptionHandler(NumberFormatException.class)
   public ModelAndView handleNumberFormatException(NumberFormatException nfex) {
      ModelAndView model = new ModelAndView("custom_error");
      model.addObject("errorMessage", nfex.getMessage());
      return model;
   }
}

@RestControllerAdvice
public class CustomJsonExceptionHandler {
   // podemos usar também @ResponseStatus
   @ResponseStatus(code =  HttpStatus.BAD_REQUEST)
   @ExceptionHandler(IllegalStateException.class)
   public String handleInvalidStateException(IllegalStateException rex, HttpServletResponse response) {
      System.err.println("Hey dev! We got an illegal state: " + rex.getMessage());
      response.addHeader("Reason", rex.getMessage());
      return "Sorry, we got some problem =(";
   }
}

Para maiores informações acessar links [2] e [3].

Exemplo

Projeto com exemplos: GitHub

Notas:

  • Ao usar Spring Bott com custom error page lembre-se de empacotar com WAR e adicionar deps do tomcat (veja [1])

Links:

  • [1] https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-jsp-limitations
  • [2] https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
  • [3] https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-error-handling-custom-error-pages

Discussion (0)