Como tratar exceções e redirecionar erros usando Spring

404-2Olá, pessoal!

Depois de um bom tempo finalmente mais um post! E como no meu serviço estamos tendo que aprender Spring Framework e Spring Boot para um projeto novo, venho aqui trazer um pouco dos recursos dessas ferramentas maravilhosas!

Antes de começar, acredito que ter um pouco mais de base seria importante, então se vocês não leram ainda os posts do Éder sobre Spring, recomendo que leiam! São os seguintes posts:

A primeira coisa que irei mostrar é como redirecionar erros http específicos para uma determinada página, por exemplo, se eu quero que um erro 404 apareça em outra página que não a padrão de erro que já tenho configurada.

Para isso, a primeira coisa que temos que fazer é configurar o bean para sobrescrever o servlet container, como no exemplo:

@Bean
public EmbeddedServletContainerCustomizer containerCustomizer(){
   return ( container -> {
       ErrorPage paginaCustom404 = new ErrorPage(HttpStatus.<em>NOT_FOUND</em>,"/404");
       container.addErrorPages(paginaCustom404);
   });
 }

Aqui foi usada uma função lambda (recurso disponível a partir do Java 8) mas nada impede que seja implementado de outro modo, apenas é necessário que você configure a ErrorPage, onde você passa o tipo de erro no primeiro parâmetro e o path (caminho da página para a qual você deseja redirecionar o erro) no segundo parâmetro, e adicione a ErrorPage no container.

Após isso basta criar e configurar seu Controller, usando a anotação @Controller em cima da sua classe que será destinada ao tratamento deste erro (ou demais erros, conforme sua necessidade). Sua classe deverá implementar a interface ErrorController e possuir ao menos um método com a anotação @RequestMapping, o qual irá mapear o erro para sua página html. No exemplo a seguir é mostrado uma forma de se fazer a implementação e configuração do Controller:

@Controller
public class CustomErrorController implements ErrorController {

       private static final String <em>ERROR_PATH </em>= "/error";
       private static final String <em>ERROR_TEMPLATE </em>= "customError";
       
       private final ErrorAttributes errorAttributes;

       @Autowired
       public CustomErrorController(ErrorAttributes errorAttributes) {
              this.errorAttributes = errorAttributes;
       }

       @RequestMapping(<em>ERROR_PATH</em>)
       public String error(Model model,HttpServletRequest request) {
              
              // {error={timestamp=Mon Nov 02 12:40:50 EST 2015, status=404, error=Not Found, message=No message available, path=/foo}}
              Map<String,Object> error = getErrorAttributes(request, true);
              
              model.addAttribute("timestamp", error.get("timestamp"));
              model.addAttribute("status", error.get("status"));
              model.addAttribute("error", error.get("error"));
              model.addAttribute("message", error.get("message"));
              model.addAttribute("path", error.get("path"));
              
              return <em>ERROR_TEMPLATE</em>;
       }

       @Override
       public String getErrorPath() {
              return <em>ERROR_PATH</em>;
       }
       
       @RequestMapping("/404")
       public String pageNotFound(Model model,HttpServletRequest request){
              model.addAttribute("error", getErrorAttributes(request,true));
              return "404";
       }
       
       private Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
              RequestAttributes requestAttributes = new ServletRequestAttributes(request);
              return this.errorAttributes.getErrorAttributes(requestAttributes,includeStackTrace);
       }
       
}

Repare que no exemplo há 2 métodos com a anotação @RequestMapping, um redirecionando para a página de erro customizada “/404” e outro para a página padrão de erros “/error“.

Agora veremos como tratar uma exceção no seu Controller de duas formas, uma tratando em um método específico e outra tratando de maneira global, ou seja, em qualquer método de qualquer Controller que ocorra determinada exceção ela será tratada do modo especificado.

Para fazer o tratamento em um método específico, basta anotá-lo com @ExceptionHandler e passar no argumento da anotação a classe da exceção que deseja tratar, como no exemplo abaixo. Note que também criei um método para facilitar o teste, que sempre lança uma Exception.

@RequestMapping("/")
public String getPost() throws Exception{              
    if (true) {
        throw new Exception("Exceção lançada!");
    }
              return "index";
}
       
@ExceptionHandler(Exception.class)
public String handleException(HttpServletRequest req, Exception exception, Model model){
     model.addAttribute("errorMessage", exception.getMessage() );
     return "error";
}

Agora, caso tenha uma exceção que poderá ocorrer em diversos outros métodos, mas que sempre será tratada do mesmo modo, podemos fazer um Global Handler Exception, para isso criamos uma classes anotada com @ControllerAdvice e nela implementamos os métodos para cada exceção que desejamos tratar, como é mostrado a seguir:

@ControllerAdvice
public class ExceptionControllerAdvice {

       @ExceptionHandler(Exception.class)
       public String exception(Exception exception, Model model){
              model.addAttribute("exception", exception);
              return "error";
       }
       
}

Vale lembrar que o retorno dos métodos que irão tratar as exceções é o nome do arquivo html que será carregado. Mas caso deseje, podemos implementar o método de tratamento de exceção sem retorno, bastando anotar também com @ResponseStatus como a abaixo.

 @ResponseStatus(value = HttpStatus.CONFLICT, reason = "Data integrity violation")
 @ExceptionHandler(DataIntegrityViolationException.class)
 public void conflict() {
 logger.error("Foi lançada DataIntegrityViolationException!");
  // Não preciso de retorno
 }

Vai aqui uma dica também: caso haja tanto um método de um Controller quanto o de um ControllerAdvice tratando a mesma exceção, o mais específico é o qual irá prevalecer, ou seja, o do Controller.

Por fim, caso se interessem, para aprender Spring Framework e Spring Boot, além de fazer muita pesquisa, comprei alguns cursos no Udemy e recomendo, tem ajudado bastante. E um curso que gostei muito foi o curso de Spring Boot do Dan Vega.

3 Comentários

  1. […] Como tratar exceções e redirecionar erros usando Spring (Autoria de Débora Adorni) […]

    Curtir

  2. […] Como tratar exceções e redirecionar erros usando Spring (Autoria de Débora Adorni) […]

    Curtir

  3. […] Como tratar exceções e redirecionar erros usando Spring (Autoria de Débora Adorni) […]

    Curtir

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

%d blogueiros gostam disto: