Spring Boot

SpringBoot

Tutorial SpringBoot: Formularios en Spring MVC

Aprende a implementar binding de formularios en Spring MVC con Thymeleaf para conectar datos HTML con objetos Java de forma eficiente y segura.

Aprende SpringBoot y certifícate

Binding de formularios con objetos con Thymeleaf

El binding de formularios es el proceso mediante el cual Spring MVC conecta automáticamente los datos enviados desde un formulario HTML con los atributos de un objeto Java. Esta funcionalidad elimina la necesidad de extraer manualmente cada campo del formulario y asignarlo a las propiedades correspondientes del objeto.

Thymeleaf facilita enormemente este proceso proporcionando atributos especiales que establecen la conexión bidireccional entre el formulario y el objeto del modelo. Cuando el usuario envía el formulario, Spring MVC utiliza esta información para poblar automáticamente el objeto con los valores introducidos.

Configuración básica del objeto modelo

Para implementar el binding, necesitamos un objeto Java que represente los datos del formulario. Este objeto debe seguir las convenciones de JavaBean, con propiedades privadas y métodos getter y setter públicos:

public class Usuario {
    private String nombre;
    private String email;
    private Integer edad;
    
    // Constructor vacío requerido
    public Usuario() {}
    
    // Getters y setters
    public String getNombre() {
        return nombre;
    }
    
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
    
    public String getEmail() {
        return email;
    }
    
    public void setEmail(String email) {
        this.email = email;
    }
    
    public Integer getEdad() {
        return edad;
    }
    
    public void setEdad(Integer edad) {
        this.edad = edad;
    }
}

Preparación del controlador

El controlador debe proporcionar una instancia del objeto al modelo para que Thymeleaf pueda establecer el binding. Esto se hace tanto para mostrar el formulario como para procesarlo:

@Controller
public class UsuarioController {
    
    @GetMapping("/usuario/nuevo")
    public String mostrarFormulario(Model model) {
        // Crear una instancia vacía para el binding
        model.addAttribute("usuario", new Usuario());
        return "formulario-usuario";
    }
    
    @PostMapping("/usuario/guardar")
    public String procesarFormulario(@ModelAttribute Usuario usuario, Model model) {
        // El objeto usuario ya contiene los datos del formulario
        // gracias al binding automático
        model.addAttribute("mensaje", "Usuario guardado: " + usuario.getNombre());
        return "resultado";
    }
}

Implementación del formulario con Thymeleaf

En la plantilla Thymeleaf, utilizamos el atributo th:object para vincular el formulario con el objeto del modelo, y th:field para conectar cada campo individual:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Registro de Usuario</title>
</head>
<body>
    <h2>Nuevo Usuario</h2>
    
    <form th:action="@{/usuario/guardar}" th:object="${usuario}" method="post">
        
        <div>
            <label for="nombre">Nombre:</label>
            <input type="text" th:field="*{nombre}" id="nombre" />
        </div>
        
        <div>
            <label for="email">Email:</label>
            <input type="email" th:field="*{email}" id="email" />
        </div>
        
        <div>
            <label for="edad">Edad:</label>
            <input type="number" th:field="*{edad}" id="edad" />
        </div>
        
        <button type="submit">Guardar</button>
    </form>
</body>
</html>

El atributo th:field="*{nombre}" es equivalente a escribir name="nombre" y value="${usuario.nombre}", pero de forma más concisa y con funcionalidades adicionales como la gestión automática de errores.

Binding con objetos anidados

Cuando trabajamos con objetos más complejos que contienen propiedades anidadas, el binding sigue funcionando utilizando la notación de punto:

public class Persona {
    private String nombre;
    private Direccion direccion;
    
    // Constructor, getters y setters
    public Persona() {
        this.direccion = new Direccion(); // Inicializar objeto anidado
    }
    
    // Resto de métodos...
}

public class Direccion {
    private String calle;
    private String ciudad;
    private String codigoPostal;
    
    // Constructor vacío, getters y setters
}

En el formulario, accedemos a las propiedades anidadas usando la sintaxis de punto:

<form th:action="@{/persona/guardar}" th:object="${persona}" method="post">
    
    <div>
        <label for="nombre">Nombre:</label>
        <input type="text" th:field="*{nombre}" id="nombre" />
    </div>
    
    <div>
        <label for="calle">Calle:</label>
        <input type="text" th:field="*{direccion.calle}" id="calle" />
    </div>
    
    <div>
        <label for="ciudad">Ciudad:</label>
        <input type="text" th:field="*{direccion.ciudad}" id="ciudad" />
    </div>
    
    <div>
        <label for="codigoPostal">Código Postal:</label>
        <input type="text" th:field="*{direccion.codigoPostal}" id="codigoPostal" />
    </div>
    
    <button type="submit">Guardar</button>
</form>

Ventajas del binding automático

El binding de formularios con Thymeleaf ofrece múltiples beneficios prácticos:

  • Reducción de código: Elimina la necesidad de extraer manualmente cada parámetro del request
  • Mantenimiento simplificado: Los cambios en el objeto se reflejan automáticamente en el formulario
  • Gestión de tipos: Spring MVC convierte automáticamente los strings del formulario a los tipos apropiados
  • Reutilización: El mismo objeto puede usarse para mostrar y procesar el formulario

Esta aproximación hace que el desarrollo de formularios sea más eficiente y menos propenso a errores, permitiendo que el desarrollador se concentre en la lógica de negocio en lugar de en los detalles de manipulación de datos del formulario.

Tipos de campos en formularios y conversiones

Spring MVC proporciona soporte automático para diferentes tipos de campos en formularios HTML, manejando las conversiones necesarias entre los strings enviados por el navegador y los tipos de datos Java correspondientes. Esta funcionalidad permite trabajar con formularios complejos de manera transparente.

Campos de texto y conversiones básicas

Los campos de texto son los más comunes y Spring MVC maneja automáticamente las conversiones básicas entre strings y tipos primitivos:

public class Producto {
    private String nombre;
    private Double precio;
    private Integer stock;
    private Boolean disponible;
    
    // Constructor vacío y getters/setters
    public Producto() {}
    
    // Getters y setters...
}

En el formulario, estos campos se renderizan como inputs de texto, pero Spring MVC los convierte automáticamente:

<form th:action="@{/producto/guardar}" th:object="${producto}" method="post">
    
    <div>
        <label for="nombre">Nombre del producto:</label>
        <input type="text" th:field="*{nombre}" id="nombre" />
    </div>
    
    <div>
        <label for="precio">Precio:</label>
        <input type="number" step="0.01" th:field="*{precio}" id="precio" />
    </div>
    
    <div>
        <label for="stock">Stock:</label>
        <input type="number" th:field="*{stock}" id="stock" />
    </div>
    
    <button type="submit">Guardar</button>
</form>

Campos de selección y checkboxes

Los campos de selección permiten al usuario elegir entre opciones predefinidas. Thymeleaf facilita la creación de estos elementos con binding automático:

public class Usuario {
    private String nombre;
    private String pais;
    private Boolean suscrito;
    private List<String> intereses;
    
    public Usuario() {
        this.intereses = new ArrayList<>();
    }
    
    // Getters y setters...
}

Selectores desplegables con opciones estáticas:

<div>
    <label for="pais">País:</label>
    <select th:field="*{pais}" id="pais">
        <option value="">Seleccionar país</option>
        <option value="ES">España</option>
        <option value="FR">Francia</option>
        <option value="IT">Italia</option>
        <option value="PT">Portugal</option>
    </select>
</div>

Checkboxes individuales para valores booleanos:

<div>
    <input type="checkbox" th:field="*{suscrito}" id="suscrito" />
    <label for="suscrito">Suscribirse al boletín</label>
</div>

Checkboxes múltiples para listas de valores:

<div>
    <label>Intereses:</label>
    <input type="checkbox" th:field="*{intereses}" value="tecnologia" id="tech" />
    <label for="tech">Tecnología</label>
    
    <input type="checkbox" th:field="*{intereses}" value="deportes" id="sports" />
    <label for="sports">Deportes</label>
    
    <input type="checkbox" th:field="*{intereses}" value="musica" id="music" />
    <label for="music">Música</label>
</div>

Campos de fecha y tiempo

Los campos de fecha requieren conversiones especiales entre strings y objetos LocalDate o LocalDateTime. Spring MVC maneja estas conversiones automáticamente:

public class Evento {
    private String titulo;
    private LocalDate fecha;
    private LocalTime hora;
    private LocalDateTime fechaCreacion;
    
    // Constructor vacío y getters/setters
}

En el formulario, utilizamos los tipos de input HTML5 apropiados:

<form th:action="@{/evento/guardar}" th:object="${evento}" method="post">
    
    <div>
        <label for="titulo">Título:</label>
        <input type="text" th:field="*{titulo}" id="titulo" />
    </div>
    
    <div>
        <label for="fecha">Fecha:</label>
        <input type="date" th:field="*{fecha}" id="fecha" />
    </div>
    
    <div>
        <label for="hora">Hora:</label>
        <input type="time" th:field="*{hora}" id="hora" />
    </div>
    
    <div>
        <label for="fechaCreacion">Fecha y hora de creación:</label>
        <input type="datetime-local" th:field="*{fechaCreacion}" id="fechaCreacion" />
    </div>
    
    <button type="submit">Crear evento</button>
</form>

Selectores con datos dinámicos

Frecuentemente necesitamos poblar selectores con datos dinámicos provenientes de la base de datos. El controlador debe proporcionar estas opciones al modelo:

@Controller
public class ProductoController {
    
    @GetMapping("/producto/nuevo")
    public String mostrarFormulario(Model model) {
        model.addAttribute("producto", new Producto());
        
        // Proporcionar opciones dinámicas
        List<Categoria> categorias = categoriaService.obtenerTodas();
        model.addAttribute("categorias", categorias);
        
        return "formulario-producto";
    }
}

En la plantilla, iteramos sobre las opciones dinámicas:

<div>
    <label for="categoria">Categoría:</label>
    <select th:field="*{categoriaId}" id="categoria">
        <option value="">Seleccionar categoría</option>
        <option th:each="categoria : ${categorias}" 
                th:value="${categoria.id}" 
                th:text="${categoria.nombre}">
        </option>
    </select>
</div>

Radio buttons para selección única

Los radio buttons permiten seleccionar una única opción de un grupo. Son útiles cuando las opciones son pocas y queremos mostrarlas todas visibles:

public class Encuesta {
    private String nombre;
    private String satisfaccion;
    
    // Constructor vacío y getters/setters
}
<div>
    <label>Nivel de satisfacción:</label>
    
    <input type="radio" th:field="*{satisfaccion}" value="muy_bajo" id="muy_bajo" />
    <label for="muy_bajo">Muy bajo</label>
    
    <input type="radio" th:field="*{satisfaccion}" value="bajo" id="bajo" />
    <label for="bajo">Bajo</label>
    
    <input type="radio" th:field="*{satisfaccion}" value="medio" id="medio" />
    <label for="medio">Medio</label>
    
    <input type="radio" th:field="*{satisfaccion}" value="alto" id="alto" />
    <label for="alto">Alto</label>
    
    <input type="radio" th:field="*{satisfaccion}" value="muy_alto" id="muy_alto" />
    <label for="muy_alto">Muy alto</label>
</div>

Áreas de texto para contenido extenso

Para contenido más largo, utilizamos áreas de texto que también se integran perfectamente con el binding:

<div>
    <label for="descripcion">Descripción:</label>
    <textarea th:field="*{descripcion}" id="descripcion" rows="4" cols="50">
    </textarea>
</div>

Conversiones personalizadas

Cuando necesitamos conversiones más complejas, Spring MVC permite definir convertidores personalizados. Por ejemplo, para convertir strings a enums:

public enum EstadoPedido {
    PENDIENTE, PROCESANDO, ENVIADO, ENTREGADO
}

public class Pedido {
    private String numero;
    private EstadoPedido estado;
    
    // Constructor vacío y getters/setters
}

El enum se maneja automáticamente en el formulario:

<div>
    <label for="estado">Estado:</label>
    <select th:field="*{estado}" id="estado">
        <option th:each="estado : ${T(com.ejemplo.EstadoPedido).values()}" 
                th:value="${estado}" 
                th:text="${estado}">
        </option>
    </select>
</div>

Esta flexibilidad en los tipos de campos permite crear formularios ricos y funcionales que se adaptan a las necesidades específicas de cada aplicación, mientras Spring MVC se encarga automáticamente de las conversiones necesarias entre la representación HTML y los objetos Java.

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 Formularios en Spring MVC 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 concepto de binding de formularios en Spring MVC y su integración con Thymeleaf.
  • Aprender a configurar objetos JavaBeans para el binding automático de datos.
  • Implementar controladores que gestionen formularios y procesen datos mediante @ModelAttribute.
  • Utilizar diferentes tipos de campos HTML (texto, selección, checkboxes, fechas, radio buttons, áreas de texto) con binding automático.
  • Manejar conversiones automáticas y personalizadas entre tipos de datos HTML y Java, incluyendo objetos anidados y enums.