Spring - Exception Handler
Wesley Egberto
Posted on April 26, 2021
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 e 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: ControllerAdvice e RestControllerAdvice. 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
Posted on April 26, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.