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ícateBinding 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.
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
Introducción Y Entorno
Spring Boot Starters
Introducción Y Entorno
Inyección De Dependencias
Introducción Y Entorno
Crear Proyecto Con Spring Initializr
Introducción Y Entorno
Crear Proyecto Desde Visual Studio Code
Introducción Y Entorno
Controladores Spring Mvc
Spring Mvc Con Thymeleaf
Vista En Spring Mvc Con Thymeleaf
Spring Mvc Con Thymeleaf
Controladores Spring Rest
Spring Mvc Con Thymeleaf
Open Api Y Cómo Agregarlo En Spring Boot
Spring Mvc Con Thymeleaf
Servicios En Spring
Spring Mvc Con Thymeleaf
Clientes Resttemplate Y Restclient
Spring Mvc Con Thymeleaf
Rxjava En Spring Web
Spring Mvc Con Thymeleaf
Métodos Post En Controladores Mvc
Spring Mvc Con Thymeleaf
Métodos Get En Controladores Mvc
Spring Mvc Con Thymeleaf
Formularios En Spring Mvc
Spring Mvc Con Thymeleaf
Crear Proyecto Con Intellij Idea
Spring Mvc Con Thymeleaf
Introducción A Los Modelos Mvc
Spring Mvc Con Thymeleaf
Layouts Y Fragmentos En Thymeleaf
Spring Mvc Con Thymeleaf
Estilización Con Bootstrap Css
Spring Mvc Con Thymeleaf
Gestión De Errores Controlleradvice
Spring Mvc Con Thymeleaf
Estilización Con Tailwind Css
Spring Mvc Con Thymeleaf
Introducción A Controladores Rest
Spring Rest
Métodos Get En Controladores Rest
Spring Rest
Métodos Post En Controladores Rest
Spring Rest
Métodos Delete En Controladores Rest
Spring Rest
Métodos Put Y Patch En Controladores Rest
Spring Rest
Gestión De Errores Restcontrolleradvice
Spring Rest
Creación De Entidades Jpa
Spring Data Jpa
Asociaciones De Entidades Jpa
Spring Data Jpa
Repositorios Spring Data
Spring Data Jpa
Métodos Find En Repositorios
Spring Data Jpa
Inserción De Datos
Spring Data Jpa
Actualizar Datos De Base De Datos
Spring Data Jpa
Borrar Datos De Base De Datos
Spring Data Jpa
Consultas Jpql Con @Query En Spring Data Jpa
Spring Data Jpa
Api Query By Example (Qbe)
Spring Data Jpa
Api Specification
Spring Data Jpa
Repositorios Reactivos
Spring Data Jpa
Configuración Base De Datos Postgresql
Spring Data Jpa
Configuración Base De Datos Mysql
Spring Data Jpa
Introducción A Jpa Y Spring Data Jpa
Spring Data Jpa
Configuración Base De Datos H2
Spring Data Jpa
Testing Unitario De Componentes Y Servicios
Testing Con Spring Test
Testing De Repositorios Spring Data Jpa
Testing Con Spring Test
Testing Controladores Spring Mvc Con Thymeleaf
Testing Con Spring Test
Testing Controladores Rest Con Json
Testing Con Spring Test
Testing De Aplicaciones Reactivas Webflux
Testing Con Spring Test
Testing De Seguridad Spring Security
Testing Con Spring Test
Testing Con Apache Kafka
Testing Con Spring Test
Introducción Al Testing
Testing Con Spring Test
Introducción A Spring Security
Seguridad Con Spring Security
Seguridad Basada En Formulario
Seguridad Con Spring Security
Registro De Usuarios En Api Rest
Seguridad Con Spring Security
Login De Usuarios En Api Rest
Seguridad Con Spring Security
Validación Jwt En Api Rest
Seguridad Con Spring Security
Autenticación Jwt Completa En Api Rest
Seguridad Con Spring Security
Seguridad Jwt En Api Rest Reactiva Spring Webflux
Seguridad Con Spring Security
Autenticación Y Autorización Con Anotaciones
Seguridad Con Spring Security
Fundamentos De Autenticación Oauth
Seguridad Con Spring Security
Autenticación Oauth Con Github
Seguridad Con Spring Security
Testing Con Spring Security Test
Seguridad Con Spring Security
Autenticación Oauth En Api Rest
Seguridad Con Spring Security
Introducción A Spring Webflux
Reactividad Webflux
Spring Data R2dbc
Reactividad Webflux
Controlador Reactivo Basado En Anotaciones
Reactividad Webflux
Controlador Reactivo Basado En Funciones
Reactividad Webflux
Operadores Reactivos Básicos
Reactividad Webflux
Operadores Reactivos Avanzados
Reactividad Webflux
Cliente Reactivo Webclient
Reactividad Webflux
Introducción E Instalación De Apache Kafka
Mensajería Asíncrona
Crear Proyecto Con Apache Kafka
Mensajería Asíncrona
Creación De Producers
Mensajería Asíncrona
Creación De Consumers
Mensajería Asíncrona
Kafka Streams En Spring Boot
Mensajería Asíncrona
Integración Con Angular
Integración Frontend
Integración Con React
Integración Frontend
Integración Con Vue
Integración Frontend
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.
Crear entidades JPA
Controladores Spring MVC
Asociaciones de entidades JPA
Creación de entidades
Reto servicio PedidoService
Reto controlador REST
Consultas JPQL
Reto test controlador REST
Anotaciones JPA
Relación ManyToOne con Tarea y Proyecto
CRUD Customers Spring MVC + Spring Data JPA
Backend API REST con Spring Boot
Filtrar categorías por nombre
Reto controlador MVC Categoría
Entidad y repositorio
Métodos derivados y consultas JPQL en repositorios
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.