Neste codelab você aprenderá a tratar erros em sua aplicação web utilizando o framework Spring Boot com Thymeleaf e acesso a dados com JdbcTemplate.
Clonar o projeto neste repositório GitHub e adicionar tratamento de erros.
@ControllerAdvice
@ExceptionHandler
Uma característica comum em todos programas de computador é a necessidade de tratar exceções. Em Java as exceções são tratadas por um mecanismo de lançamento de exceções quando o erro é identificado. Spring Boot oferece diversas maneiras de tratar exceções. Uma forma simples e poderosa que usaremos aqui neste tutorial é a anotação @ControllerAdvice
.
Esta anotação facilita nossa vida para lidar com todos os tipos de exceções em um local central em nossa aplicação. A facilidade está em não precisar capturar exceções em cada método ou classe separadamente, bastando apenas lançar a exceção no método e, em seguida, ela será capturada na classe central de tratamento de exceções anotada por @ControllerAdvice
.
Divisão por zero - java.lang.ArithmeticException: / by zero
public class Teste { public static void main(String[] args) { System.out.println("chamando m1()"); m1(); System.out.println("fim do método main"); } private static void m1() { System.out.println("chamando m2()"); m2(); System.out.println("fim do método m1()"); } private static void m2() { System.out.println("início do m2()"); int x = 1 / 0; System.out.println("fim do método m2()"); } }
Depois de executar o programa acima teremos o seguinte:
Como tratar este erro? Vamos modificar o código anterior para exemplificar
package com.professorangoti.condominio; public class Teste { public static void main(String[] args) { System.out.println("chamando m1()"); m1(); System.out.println("fim do método main"); } private static void m1() { System.out.println("chamando m2()"); m2(); System.out.println("fim do método m1()"); } private static void m2() { System.out.println("início do m2()"); try { // colocar o código com potencial de erro dentro do bloco try int x = 1 / 0; } catch (ArithmeticException e) { //capturar as exceções que podem ocorrer System.out.println("Erro: " + e.getMessage()); } System.out.println("fim do método m2()"); } }
Depois de executar o programa acima teremos o seguinte:
O bloco try/catch não deixa o programa parar, tratando o erro no local onde aconteceu. Se as exceções capturadas forem de mesma hierarquia, as classes mais especializadas devem aparecer primeiro. Para capturar qualquer exceção use a classe Exception
(não indicado):
catch (
Exception
e) { ... }
Podemos também delegar o tratamento do erro para outro método na pilha de execução, para isso podemos lançar uma exceção .
A classe que será criada para fazer o papel de central de tratamento de exceções deverá ser anotada com a anotação @ControllerAdvice
. Nesta classe vamos usar a seguinte anotação em seus métodos:
@ExceptionHandler
: você deverá fornecer as exceções tratadas pelo métodoEsta anotação vai funcionar como um filtro para capturar uma exceção específica, possibilitando o tratamento do erro.
Classe MyControllerAdvice
import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.servlet.mvc.support.RedirectAttributes; @ControllerAdvice public class MyControllerAdvice { @ExceptionHandler(java.sql.SQLIntegrityConstraintViolationException.class) public String violaçãoDeIntegridade(java.sql.SQLIntegrityConstraintViolationException ex, final RedirectAttributes redirectAttributes) { String errorMessage = ex.getMessage(); if (errorMessage.contains("Cannot delete or update a parent row")) { redirectAttributes.addFlashAttribute("mensagem", "O proprietário tem apartamento cadastrado. Não é possível excluí-lo do sistema"); return "redirect:/rel_prop"; } return "error"; } }
Esta classe deve estar no mesmo pacote das classes controladoras (pacote controller)
.
Precisamos alterar o template rel_prop.html
para exibir a mensagem de erro:
<!DOCTYPE html> <html th:include="template :: modelo"> <body> <div th:fragment="conteudo"> <div th:if="${mensagem}" th:text="${mensagem}" class="p-3 mb-2 bg-warning text-dark"> </div> <table class="table"> <thead> <tr> <th scope="col">#</th> <th scope="col">Nome</th> <th scope="col">Telefone</th> <th scope="col">Ações</th> </tr> </thead> <tbody> <tr th:each="prop : ${proprietarios}"> <th scope="row" th:text="${prop.id}"></th> <td th:text="${prop.nome}"></td> <td th:text="${prop.telefone}"></td> <td> <a th:href="@{/excluir_prop(id=*{prop.id})}">Excluir</a> </td> </tr> </tbody> </table> </div> </body> </html>