DEV Community

Wesley Egberto
Wesley Egberto

Posted on • Edited on

1

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

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay