Spring Boot

SpringBoot

Tutorial SpringBoot: Gestión de errores ControllerAdvice

Aprende a manejar excepciones en Spring MVC usando @ExceptionHandler y @ControllerAdvice para un control global y eficiente de errores.

Aprende SpringBoot y certifícate

Excepciones con @ExceptionHandler

La gestión de errores en aplicaciones web MVC requiere un enfoque estructurado para proporcionar una experiencia de usuario coherente cuando algo sale mal. Spring MVC ofrece la anotación @ExceptionHandler como mecanismo fundamental para capturar y manejar excepciones específicas dentro de nuestros controladores.

Cuando una excepción se produce durante la ejecución de un método de controlador, Spring busca automáticamente un método anotado con @ExceptionHandler que pueda manejar ese tipo específico de excepción. Este enfoque nos permite centralizar la lógica de manejo de errores y proporcionar respuestas personalizadas según el tipo de problema que haya ocurrido.

Implementación básica de @ExceptionHandler

Un método @ExceptionHandler se define dentro del mismo controlador donde pueden ocurrir las excepciones. La anotación especifica qué tipos de excepción debe capturar:

@Controller
public class ProductoController {
    
    @GetMapping("/producto/{id}")
    public String mostrarProducto(@PathVariable Long id, Model model) {
        if (id <= 0) {
            throw new IllegalArgumentException("El ID del producto debe ser positivo");
        }
        
        Producto producto = buscarProducto(id);
        if (producto == null) {
            throw new ProductoNoEncontradoException("Producto no encontrado con ID: " + id);
        }
        
        model.addAttribute("producto", producto);
        return "producto/detalle";
    }
    
    @ExceptionHandler(IllegalArgumentException.class)
    public String manejarArgumentoInvalido(IllegalArgumentException ex, Model model) {
        model.addAttribute("error", "Parámetro inválido: " + ex.getMessage());
        return "error/parametro-invalido";
    }
    
    @ExceptionHandler(ProductoNoEncontradoException.class)
    public String manejarProductoNoEncontrado(ProductoNoEncontradoException ex, Model model) {
        model.addAttribute("error", ex.getMessage());
        model.addAttribute("codigo", "PRODUCTO_NO_ENCONTRADO");
        return "error/no-encontrado";
    }
}

En este ejemplo, cada método @ExceptionHandler maneja un tipo específico de excepción y devuelve una vista personalizada con información relevante sobre el error.

Manejo de múltiples excepciones

Un solo método puede manejar múltiples tipos de excepción especificándolos en un array dentro de la anotación:

@Controller
public class UsuarioController {
    
    @PostMapping("/usuario/registro")
    public String registrarUsuario(@ModelAttribute Usuario usuario, Model model) {
        validarUsuario(usuario);
        guardarUsuario(usuario);
        return "redirect:/usuario/exito";
    }
    
    @ExceptionHandler({ValidationException.class, DataIntegrityViolationException.class})
    public String manejarErroresValidacion(Exception ex, Model model) {
        String mensaje = determinarMensajeError(ex);
        model.addAttribute("error", mensaje);
        model.addAttribute("usuario", new Usuario()); // Para repoblar el formulario
        return "usuario/registro";
    }
    
    private String determinarMensajeError(Exception ex) {
        if (ex instanceof ValidationException) {
            return "Los datos proporcionados no son válidos";
        } else if (ex instanceof DataIntegrityViolationException) {
            return "El email ya está registrado en el sistema";
        }
        return "Error durante el registro";
    }
}

Acceso a información adicional del contexto

Los métodos @ExceptionHandler pueden recibir varios parámetros que proporcionan información adicional sobre el contexto de la excepción:

@Controller
public class PedidoController {
    
    @PostMapping("/pedido/procesar")
    public String procesarPedido(@ModelAttribute Pedido pedido) {
        if (pedido.getTotal().compareTo(BigDecimal.ZERO) <= 0) {
            throw new PedidoInvalidoException("El total del pedido debe ser mayor que cero");
        }
        
        procesarPago(pedido);
        return "pedido/confirmacion";
    }
    
    @ExceptionHandler(PedidoInvalidoException.class)
    public String manejarPedidoInvalido(
            PedidoInvalidoException ex,
            HttpServletRequest request,
            Model model) {
        
        // Información sobre la excepción
        model.addAttribute("error", ex.getMessage());
        model.addAttribute("timestamp", LocalDateTime.now());
        
        // Información sobre la petición
        model.addAttribute("url", request.getRequestURL().toString());
        model.addAttribute("metodo", request.getMethod());
        
        // Datos para repoblar el formulario
        model.addAttribute("pedido", new Pedido());
        
        return "pedido/error";
    }
}

Jerarquía de excepciones y especificidad

Spring MVC respeta la jerarquía de excepciones al buscar el manejador más específico. Si tenemos manejadores para una excepción padre y una hija, Spring elegirá el más específico:

@Controller
public class FileController {
    
    @PostMapping("/archivo/subir")
    public String subirArchivo(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            throw new ArchivoVacioException("El archivo está vacío");
        }
        
        if (file.getSize() > 5_000_000) {
            throw new ArchivoDemasiadoGrandeException("El archivo supera los 5MB");
        }
        
        guardarArchivo(file);
        return "archivo/exito";
    }
    
    // Manejador específico para archivos vacíos
    @ExceptionHandler(ArchivoVacioException.class)
    public String manejarArchivoVacio(ArchivoVacioException ex, Model model) {
        model.addAttribute("error", "Debe seleccionar un archivo válido");
        model.addAttribute("tipo", "archivo-vacio");
        return "archivo/error-especifico";
    }
    
    // Manejador específico para archivos grandes
    @ExceptionHandler(ArchivoDemasiadoGrandeException.class)
    public String manejarArchivoGrande(ArchivoDemasiadoGrandeException ex, Model model) {
        model.addAttribute("error", "El archivo es demasiado grande");
        model.addAttribute("limite", "5MB");
        return "archivo/error-tamaño";
    }
    
    // Manejador genérico para cualquier excepción de archivo
    @ExceptionHandler(ArchivoException.class)
    public String manejarErrorArchivo(ArchivoException ex, Model model) {
        model.addAttribute("error", "Error procesando el archivo: " + ex.getMessage());
        return "archivo/error-generico";
    }
}

Limitaciones del alcance local

Es importante entender que los métodos @ExceptionHandler definidos en un controlador solo manejan excepciones que ocurren dentro de ese mismo controlador. Si la misma excepción se produce en otro controlador, necesitaríamos duplicar el código del manejador o buscar una solución más global.

@Controller
public class ControladorA {
    
    @GetMapping("/ruta-a")
    public String metodoA() {
        throw new MiExcepcionPersonalizada("Error en controlador A");
    }
    
    @ExceptionHandler(MiExcepcionPersonalizada.class)
    public String manejarMiExcepcion(MiExcepcionPersonalizada ex, Model model) {
        model.addAttribute("error", ex.getMessage());
        return "error/mi-error";
    }
}

@Controller
public class ControladorB {
    
    @GetMapping("/ruta-b")
    public String metodoB() {
        // Esta excepción NO será manejada por el @ExceptionHandler del ControladorA
        throw new MiExcepcionPersonalizada("Error en controlador B");
    }
    
    // Necesitaríamos duplicar el manejador aquí para capturar la excepción
}

Esta limitación hace que @ExceptionHandler sea ideal para manejar excepciones específicas de un controlador particular, pero requiere soluciones adicionales cuando necesitamos un manejo de errores más amplio en toda la aplicación.

Excepciones globales con @ControllerAdvice

Cuando necesitamos manejar excepciones de manera consistente en toda nuestra aplicación MVC, duplicar métodos @ExceptionHandler en cada controlador se convierte en una tarea repetitiva y propensa a errores. Spring MVC proporciona @ControllerAdvice como solución para centralizar el manejo de excepciones a nivel global.

Una clase anotada con @ControllerAdvice actúa como un interceptor que puede capturar excepciones lanzadas desde cualquier controlador de la aplicación. Esto nos permite definir una única vez cómo manejar tipos específicos de excepciones, manteniendo la consistencia en toda la aplicación.

Creación de un manejador global básico

Para implementar un manejador global, creamos una clase dedicada anotada con @ControllerAdvice y definimos nuestros métodos @ExceptionHandler:

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(IllegalArgumentException.class)
    public String manejarArgumentoInvalido(IllegalArgumentException ex, Model model) {
        model.addAttribute("error", "Parámetro inválido: " + ex.getMessage());
        model.addAttribute("timestamp", LocalDateTime.now());
        return "error/parametro-invalido";
    }
    
    @ExceptionHandler(AccessDeniedException.class)
    public String manejarAccesoDenegado(AccessDeniedException ex, Model model) {
        model.addAttribute("error", "No tienes permisos para acceder a este recurso");
        model.addAttribute("codigo", "ACCESS_DENIED");
        return "error/acceso-denegado";
    }
    
    @ExceptionHandler(Exception.class)
    public String manejarErrorGeneral(Exception ex, Model model, HttpServletRequest request) {
        model.addAttribute("error", "Ha ocurrido un error inesperado");
        model.addAttribute("url", request.getRequestURL().toString());
        model.addAttribute("timestamp", LocalDateTime.now());
        
        // Log del error para debugging
        System.err.println("Error no manejado: " + ex.getMessage());
        ex.printStackTrace();
        
        return "error/general";
    }
}

Jerarquía de manejo de excepciones

Cuando usamos @ControllerAdvice junto con @ExceptionHandler locales, Spring sigue una jerarquía específica de resolución. Los manejadores locales del controlador tienen prioridad sobre los globales:

@Controller
public class ProductoController {
    
    @GetMapping("/producto/{id}")
    public String mostrarProducto(@PathVariable Long id, Model model) {
        if (id <= 0) {
            throw new IllegalArgumentException("ID inválido en ProductoController");
        }
        return "producto/detalle";
    }
    
    // Este manejador local tiene prioridad sobre el global
    @ExceptionHandler(IllegalArgumentException.class)
    public String manejarArgumentoInvalidoLocal(IllegalArgumentException ex, Model model) {
        model.addAttribute("error", "Error específico de producto: " + ex.getMessage());
        return "producto/error-parametro";
    }
}

@Controller
public class UsuarioController {
    
    @GetMapping("/usuario/{id}")
    public String mostrarUsuario(@PathVariable Long id, Model model) {
        if (id <= 0) {
            // Esta excepción será manejada por el @ControllerAdvice global
            throw new IllegalArgumentException("ID inválido en UsuarioController");
        }
        return "usuario/detalle";
    }
}

Manejo de excepciones específicas del dominio

Una práctica común es crear excepciones personalizadas para diferentes aspectos del negocio y manejarlas globalmente:

// Excepciones personalizadas
public class RecursoNoEncontradoException extends RuntimeException {
    public RecursoNoEncontradoException(String mensaje) {
        super(mensaje);
    }
}

public class ValidacionNegocioException extends RuntimeException {
    private final String campo;
    
    public ValidacionNegocioException(String campo, String mensaje) {
        super(mensaje);
        this.campo = campo;
    }
    
    public String getCampo() { return campo; }
}

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(RecursoNoEncontradoException.class)
    public String manejarRecursoNoEncontrado(RecursoNoEncontradoException ex, Model model) {
        model.addAttribute("error", ex.getMessage());
        model.addAttribute("tipo", "recurso-no-encontrado");
        return "error/no-encontrado";
    }
    
    @ExceptionHandler(ValidacionNegocioException.class)
    public String manejarValidacionNegocio(ValidacionNegocioException ex, Model model) {
        model.addAttribute("error", ex.getMessage());
        model.addAttribute("campo", ex.getCampo());
        model.addAttribute("tipo", "validacion-negocio");
        return "error/validacion";
    }
}

Limitación del alcance con basePackages

Podemos restringir el alcance de un @ControllerAdvice para que solo afecte a controladores específicos usando el atributo basePackages:

@ControllerAdvice(basePackages = "com.empresa.tienda.controller.admin")
public class AdminExceptionHandler {
    
    @ExceptionHandler(SecurityException.class)
    public String manejarErrorSeguridad(SecurityException ex, Model model) {
        model.addAttribute("error", "Error de seguridad en área administrativa");
        model.addAttribute("redirectUrl", "/admin/login");
        return "admin/error-seguridad";
    }
}

@ControllerAdvice(basePackages = "com.empresa.tienda.controller.publico")
public class PublicoExceptionHandler {
    
    @ExceptionHandler(SecurityException.class)
    public String manejarErrorSeguridadPublico(SecurityException ex, Model model) {
        model.addAttribute("error", "Acceso no autorizado");
        model.addAttribute("redirectUrl", "/login");
        return "publico/error-acceso";
    }
}

Información contextual enriquecida

Los manejadores globales pueden aprovechar la información del contexto para proporcionar respuestas más informativas:

@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(DataAccessException.class)
    public String manejarErrorBaseDatos(
            DataAccessException ex, 
            HttpServletRequest request,
            Model model) {
        
        // Información del error
        model.addAttribute("error", "Error temporal del sistema. Inténtalo más tarde.");
        model.addAttribute("timestamp", LocalDateTime.now());
        
        // Información de la petición para debugging
        model.addAttribute("url", request.getRequestURL().toString());
        model.addAttribute("metodo", request.getMethod());
        model.addAttribute("userAgent", request.getHeader("User-Agent"));
        
        // Información del usuario si está disponible
        String usuario = request.getRemoteUser();
        if (usuario != null) {
            model.addAttribute("usuario", usuario);
        }
        
        // Log detallado para el equipo técnico
        System.err.println("Error de base de datos en " + request.getRequestURL() + 
                          " para usuario " + usuario + ": " + ex.getMessage());
        
        return "error/sistema-temporal";
    }
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public String manejarValidacionFormulario(
            MethodArgumentNotValidException ex,
            Model model,
            HttpServletRequest request) {
        
        // Extraer errores de validación
        List<String> errores = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(error -> error.getField() + ": " + error.getDefaultMessage())
                .collect(Collectors.toList());
        
        model.addAttribute("errores", errores);
        model.addAttribute("formulario", request.getRequestURI());
        
        return "error/validacion-formulario";
    }
}

Organización de múltiples manejadores globales

En aplicaciones grandes, es recomendable organizar los manejadores globales por responsabilidad o módulo:

@ControllerAdvice
@Order(1) // Prioridad alta
public class SecurityExceptionHandler {
    
    @ExceptionHandler({AccessDeniedException.class, AuthenticationException.class})
    public String manejarErroresSeguridad(Exception ex, Model model) {
        model.addAttribute("error", "Error de autenticación o autorización");
        return "error/seguridad";
    }
}

@ControllerAdvice
@Order(2) // Prioridad media
public class BusinessExceptionHandler {
    
    @ExceptionHandler({ValidacionNegocioException.class, RecursoNoEncontradoException.class})
    public String manejarErroresNegocio(Exception ex, Model model) {
        model.addAttribute("error", ex.getMessage());
        return "error/negocio";
    }
}

@ControllerAdvice
@Order(3) // Prioridad baja - captura todo lo demás
public class GeneralExceptionHandler {
    
    @ExceptionHandler(Exception.class)
    public String manejarErrorGeneral(Exception ex, Model model) {
        model.addAttribute("error", "Error inesperado del sistema");
        return "error/general";
    }
}

La anotación @Order determina el orden de evaluación cuando múltiples @ControllerAdvice pueden manejar la misma excepción, siendo los números más bajos de mayor prioridad.

Página de error por defecto y personalizada en Spring MVC

Además del manejo programático de excepciones con @ExceptionHandler y @ControllerAdvice, Spring MVC proporciona un mecanismo automático para gestionar errores HTTP estándar como 404, 500 o 403. Este sistema permite crear páginas de error personalizadas que mejoran significativamente la experiencia del usuario cuando ocurren problemas en la aplicación.

Spring Boot incluye una página de error por defecto que se activa automáticamente cuando no existe un manejador específico para una excepción o cuando se produce un error HTTP estándar. Esta página muestra información básica sobre el error, pero para aplicaciones en producción necesitamos páginas más amigables y coherentes con el diseño de nuestra aplicación.

Configuración de páginas de error personalizadas

Spring MVC busca automáticamente plantillas de error en el directorio src/main/resources/templates/error/ siguiendo una convención específica de nombres. Podemos crear páginas personalizadas usando el código de estado HTTP como nombre del archivo:

src/main/resources/templates/error/
├── 404.html          # Error "No encontrado"
├── 500.html          # Error interno del servidor
├── 403.html          # Acceso prohibido
└── 4xx.html          # Cualquier error 4xx no específico

Una página de error básica en Thymeleaf podría verse así:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Página no encontrada</title>
    <link rel="stylesheet" th:href="@{/css/styles.css}">
</head>
<body>
    <div class="error-container">
        <h1>¡Oops! Página no encontrada</h1>
        <p>La página que buscas no existe o ha sido movida.</p>
        
        <div class="error-details">
            <p><strong>Código de error:</strong> <span th:text="${status}">404</span></p>
            <p><strong>Mensaje:</strong> <span th:text="${error}">Not Found</span></p>
            <p><strong>Ruta solicitada:</strong> <span th:text="${path}">/ruta/inexistente</span></p>
        </div>
        
        <div class="error-actions">
            <a th:href="@{/}" class="btn btn-primary">Volver al inicio</a>
            <a th:href="@{/contacto}" class="btn btn-secondary">Contactar soporte</a>
        </div>
    </div>
</body>
</html>

Variables disponibles en páginas de error

Spring MVC proporciona automáticamente varias variables de contexto que podemos usar en nuestras plantillas de error:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Error del servidor</title>
    <link rel="stylesheet" th:href="@{/css/error.css}">
</head>
<body>
    <div class="error-page">
        <h1>Error interno del servidor</h1>
        <p>Estamos experimentando dificultades técnicas temporales.</p>
        
        <!-- Variables automáticas disponibles -->
        <div class="error-info" th:if="${#ctx.containsVariable('timestamp')}">
            <p><strong>Timestamp:</strong> <span th:text="${timestamp}"></span></p>
            <p><strong>Status:</strong> <span th:text="${status}">500</span></p>
            <p><strong>Error:</strong> <span th:text="${error}">Internal Server Error</span></p>
            <p><strong>Path:</strong> <span th:text="${path}">/ruta/error</span></p>
        </div>
        
        <!-- Mostrar mensaje solo en desarrollo -->
        <div th:if="${message and #strings.length(message) > 0}" class="debug-info">
            <h3>Información técnica:</h3>
            <p th:text="${message}">Mensaje de error detallado</p>
        </div>
        
        <div class="help-section">
            <h3>¿Qué puedes hacer?</h3>
            <ul>
                <li>Espera unos minutos e inténtalo de nuevo</li>
                <li>Verifica que la URL sea correcta</li>
                <li>Contacta con nuestro equipo de soporte</li>
            </ul>
        </div>
        
        <a th:href="@{/}" class="return-home">Volver al inicio</a>
    </div>
</body>
</html>

Jerarquía de resolución de páginas de error

Spring MVC sigue una jerarquía específica para resolver qué página de error mostrar, desde la más específica hasta la más general:

1 - Código exacto: 404.html para errores 404

2 - Rango de códigos: 4xx.html para cualquier error 4xx

3 - Página genérica: error.html para cualquier error

<!-- src/main/resources/templates/error/4xx.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Error de cliente</title>
</head>
<body>
    <div class="client-error">
        <h1>Error en la solicitud</h1>
        
        <!-- Personalizar mensaje según el código específico -->
        <div th:switch="${status}">
            <p th:case="400">La solicitud contiene datos incorrectos.</p>
            <p th:case="401">Necesitas iniciar sesión para acceder.</p>
            <p th:case="403">No tienes permisos para esta acción.</p>
            <p th:case="404">La página solicitada no existe.</p>
            <p th:case="*">Ha ocurrido un error con tu solicitud.</p>
        </div>
        
        <p><strong>Código:</strong> <span th:text="${status}"></span></p>
        <a th:href="@{/}">Volver al inicio</a>
    </div>
</body>
</html>

Configuración personalizada del manejo de errores

Podemos personalizar el comportamiento del manejo de errores implementando ErrorController para casos más complejos:

@Controller
public class CustomErrorController implements ErrorController {
    
    private static final String ERROR_PATH = "/error";
    
    @RequestMapping(ERROR_PATH)
    public String handleError(HttpServletRequest request, Model model) {
        // Obtener información del error
        Integer statusCode = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
        String errorMessage = (String) request.getAttribute(RequestDispatcher.ERROR_MESSAGE);
        String requestUri = (String) request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI);
        
        // Agregar información al modelo
        model.addAttribute("status", statusCode);
        model.addAttribute("error", getErrorMessage(statusCode));
        model.addAttribute("message", errorMessage);
        model.addAttribute("path", requestUri);
        model.addAttribute("timestamp", LocalDateTime.now());
        
        // Determinar qué plantilla usar
        if (statusCode != null) {
            if (statusCode == 404) {
                return "error/404";
            } else if (statusCode >= 500) {
                return "error/5xx";
            } else if (statusCode >= 400) {
                return "error/4xx";
            }
        }
        
        return "error/general";
    }
    
    private String getErrorMessage(Integer statusCode) {
        if (statusCode == null) return "Error desconocido";
        
        return switch (statusCode) {
            case 400 -> "Solicitud incorrecta";
            case 401 -> "No autorizado";
            case 403 -> "Acceso prohibido";
            case 404 -> "Página no encontrada";
            case 500 -> "Error interno del servidor";
            case 503 -> "Servicio no disponible";
            default -> "Error HTTP " + statusCode;
        };
    }
}

Configuración de propiedades de error

Spring Boot permite configurar varios aspectos del manejo de errores a través del archivo application.properties:

# Incluir información detallada del error (solo desarrollo)
server.error.include-message=on_param
server.error.include-binding-errors=on_param
server.error.include-stacktrace=on_param
server.error.include-exception=false

# Ruta personalizada para el endpoint de error
server.error.path=/error

# Configuración de páginas de error estáticas
spring.web.resources.static-locations=classpath:/static/,classpath:/public/

Para entornos de producción, es recomendable mantener la información de error al mínimo para evitar exponer detalles técnicos sensibles:

# Configuración para producción
server.error.include-message=never
server.error.include-binding-errors=never
server.error.include-stacktrace=never
server.error.include-exception=false

Integración con el diseño de la aplicación

Las páginas de error deben mantener la coherencia visual con el resto de la aplicación. Podemos usar fragmentos de Thymeleaf para reutilizar elementos comunes:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Error - Mi Aplicación</title>
    <div th:replace="fragments/head :: head"></div>
</head>
<body>
    <!-- Header común de la aplicación -->
    <div th:replace="fragments/header :: header"></div>
    
    <main class="error-main">
        <div class="container">
            <div class="error-content">
                <img th:src="@{/images/error-icon.svg}" alt="Error" class="error-icon">
                <h1>¡Algo salió mal!</h1>
                
                <div class="error-message" th:switch="${status}">
                    <p th:case="404">La página que buscas no existe.</p>
                    <p th:case="500">Estamos solucionando un problema técnico.</p>
                    <p th:case="*">Ha ocurrido un error inesperado.</p>
                </div>
                
                <div class="error-actions">
                    <a th:href="@{/}" class="btn btn-primary">Ir al inicio</a>
                    <button onclick="history.back()" class="btn btn-secondary">Volver atrás</button>
                </div>
            </div>
        </div>
    </main>
    
    <!-- Footer común de la aplicación -->
    <div th:replace="fragments/footer :: footer"></div>
</body>
</html>

Este enfoque asegura que las páginas de error mantengan la navegación, estilos y estructura general de la aplicación, proporcionando una experiencia de usuario más coherente incluso cuando algo sale mal.

Aprende SpringBoot online

Otras lecciones de SpringBoot

Accede a todas las lecciones de SpringBoot y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A Spring Boot

Spring Boot

Introducción Y Entorno

Spring Boot Starters

Spring Boot

Introducción Y Entorno

Inyección De Dependencias

Spring Boot

Introducción Y Entorno

Crear Proyecto Con Spring Initializr

Spring Boot

Introducción Y Entorno

Crear Proyecto Desde Visual Studio Code

Spring Boot

Introducción Y Entorno

Controladores Spring Mvc

Spring Boot

Spring Mvc Con Thymeleaf

Vista En Spring Mvc Con Thymeleaf

Spring Boot

Spring Mvc Con Thymeleaf

Controladores Spring Rest

Spring Boot

Spring Mvc Con Thymeleaf

Open Api Y Cómo Agregarlo En Spring Boot

Spring Boot

Spring Mvc Con Thymeleaf

Servicios En Spring

Spring Boot

Spring Mvc Con Thymeleaf

Clientes Resttemplate Y Restclient

Spring Boot

Spring Mvc Con Thymeleaf

Rxjava En Spring Web

Spring Boot

Spring Mvc Con Thymeleaf

Métodos Post En Controladores Mvc

Spring Boot

Spring Mvc Con Thymeleaf

Métodos Get En Controladores Mvc

Spring Boot

Spring Mvc Con Thymeleaf

Formularios En Spring Mvc

Spring Boot

Spring Mvc Con Thymeleaf

Crear Proyecto Con Intellij Idea

Spring Boot

Spring Mvc Con Thymeleaf

Introducción A Los Modelos Mvc

Spring Boot

Spring Mvc Con Thymeleaf

Layouts Y Fragmentos En Thymeleaf

Spring Boot

Spring Mvc Con Thymeleaf

Estilización Con Bootstrap Css

Spring Boot

Spring Mvc Con Thymeleaf

Gestión De Errores Controlleradvice

Spring Boot

Spring Mvc Con Thymeleaf

Estilización Con Tailwind Css

Spring Boot

Spring Mvc Con Thymeleaf

Introducción A Controladores Rest

Spring Boot

Spring Rest

Métodos Get En Controladores Rest

Spring Boot

Spring Rest

Métodos Post En Controladores Rest

Spring Boot

Spring Rest

Métodos Delete En Controladores Rest

Spring Boot

Spring Rest

Métodos Put Y Patch En Controladores Rest

Spring Boot

Spring Rest

Gestión De Errores Restcontrolleradvice

Spring Boot

Spring Rest

Creación De Entidades Jpa

Spring Boot

Spring Data Jpa

Asociaciones De Entidades Jpa

Spring Boot

Spring Data Jpa

Repositorios Spring Data

Spring Boot

Spring Data Jpa

Métodos Find En Repositorios

Spring Boot

Spring Data Jpa

Inserción De Datos

Spring Boot

Spring Data Jpa

Actualizar Datos De Base De Datos

Spring Boot

Spring Data Jpa

Borrar Datos De Base De Datos

Spring Boot

Spring Data Jpa

Consultas Jpql Con @Query En Spring Data Jpa

Spring Boot

Spring Data Jpa

Api Query By Example (Qbe)

Spring Boot

Spring Data Jpa

Api Specification

Spring Boot

Spring Data Jpa

Repositorios Reactivos

Spring Boot

Spring Data Jpa

Configuración Base De Datos Postgresql

Spring Boot

Spring Data Jpa

Configuración Base De Datos Mysql

Spring Boot

Spring Data Jpa

Introducción A Jpa Y Spring Data Jpa

Spring Boot

Spring Data Jpa

Configuración Base De Datos H2

Spring Boot

Spring Data Jpa

Testing Unitario De Componentes Y Servicios

Spring Boot

Testing Con Spring Test

Testing De Repositorios Spring Data Jpa

Spring Boot

Testing Con Spring Test

Testing Controladores Spring Mvc Con Thymeleaf

Spring Boot

Testing Con Spring Test

Testing Controladores Rest Con Json

Spring Boot

Testing Con Spring Test

Testing De Aplicaciones Reactivas Webflux

Spring Boot

Testing Con Spring Test

Testing De Seguridad Spring Security

Spring Boot

Testing Con Spring Test

Testing Con Apache Kafka

Spring Boot

Testing Con Spring Test

Introducción Al Testing

Spring Boot

Testing Con Spring Test

Introducción A Spring Security

Spring Boot

Seguridad Con Spring Security

Seguridad Basada En Formulario

Spring Boot

Seguridad Con Spring Security

Registro De Usuarios En Api Rest

Spring Boot

Seguridad Con Spring Security

Login De Usuarios En Api Rest

Spring Boot

Seguridad Con Spring Security

Validación Jwt En Api Rest

Spring Boot

Seguridad Con Spring Security

Autenticación Jwt Completa En Api Rest

Spring Boot

Seguridad Con Spring Security

Seguridad Jwt En Api Rest Reactiva Spring Webflux

Spring Boot

Seguridad Con Spring Security

Autenticación Y Autorización Con Anotaciones

Spring Boot

Seguridad Con Spring Security

Fundamentos De Autenticación Oauth

Spring Boot

Seguridad Con Spring Security

Autenticación Oauth Con Github

Spring Boot

Seguridad Con Spring Security

Testing Con Spring Security Test

Spring Boot

Seguridad Con Spring Security

Autenticación Oauth En Api Rest

Spring Boot

Seguridad Con Spring Security

Introducción A Spring Webflux

Spring Boot

Reactividad Webflux

Spring Data R2dbc

Spring Boot

Reactividad Webflux

Controlador Reactivo Basado En Anotaciones

Spring Boot

Reactividad Webflux

Controlador Reactivo Basado En Funciones

Spring Boot

Reactividad Webflux

Operadores Reactivos Básicos

Spring Boot

Reactividad Webflux

Operadores Reactivos Avanzados

Spring Boot

Reactividad Webflux

Cliente Reactivo Webclient

Spring Boot

Reactividad Webflux

Introducción E Instalación De Apache Kafka

Spring Boot

Mensajería Asíncrona

Crear Proyecto Con Apache Kafka

Spring Boot

Mensajería Asíncrona

Creación De Producers

Spring Boot

Mensajería Asíncrona

Creación De Consumers

Spring Boot

Mensajería Asíncrona

Kafka Streams En Spring Boot

Spring Boot

Mensajería Asíncrona

Integración Con Angular

Spring Boot

Integración Frontend

Integración Con React

Spring Boot

Integración Frontend

Integración Con Vue

Spring Boot

Integración Frontend

Accede GRATIS a SpringBoot y certifícate

Ejercicios de programación de SpringBoot

Evalúa tus conocimientos de esta lección Gestión de errores ControllerAdvice con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender el uso de @ExceptionHandler para manejar excepciones específicas en controladores.
  • Aprender a centralizar el manejo de errores con @ControllerAdvice para excepciones globales.
  • Conocer la jerarquía y prioridad entre manejadores locales y globales de excepciones.
  • Configurar páginas de error personalizadas para mejorar la experiencia del usuario ante errores HTTP.
  • Integrar información contextual y organizar múltiples manejadores globales para una gestión eficiente de errores.