Vista en Spring MVC con Thymeleaf

Intermedio
SpringBoot
SpringBoot
Actualizado: 12/06/2025

¡Desbloquea el curso completo!

IA
Ejercicios
Certificado
Entrar

Sintaxis básica th: y expresiones básicas ${}

Thymeleaf utiliza una sintaxis basada en atributos HTML que permite integrar lógica de presentación directamente en las plantillas. Los atributos de Thymeleaf siempre comienzan con el prefijo th: seguido del nombre del atributo HTML que queremos modificar o controlar.

Atributos th: fundamentales

Los atributos th: reemplazan o modifican los atributos HTML estándar. Cuando Thymeleaf procesa una plantilla, evalúa estos atributos y genera el HTML final que se envía al navegador.

<!-- Atributo th:text reemplaza el contenido del elemento -->
<p th:text="'Hola mundo'">Texto por defecto</p>

<!-- Resultado: <p>Hola mundo</p> -->

El atributo th:text es uno de los más utilizados. Establece el contenido textual de un elemento, escapando automáticamente caracteres especiales para prevenir ataques XSS:

<h1 th:text="${titulo}">Título por defecto</h1>
<span th:text="${usuario.nombre}">Nombre usuario</span>

Para modificar atributos HTML específicos, utilizamos la sintaxis th: seguida del nombre del atributo:

<!-- Modificar el atributo src de una imagen -->
<img th:src="${rutaImagen}" src="imagen-defecto.jpg" alt="Imagen">

<!-- Modificar el atributo href de un enlace -->
<a th:href="${enlace}" href="#" th:text="${textoEnlace}">Enlace</a>

<!-- Modificar el atributo value de un input -->
<input type="text" th:value="${valorCampo}" value="">

Expresiones básicas ${}

Las expresiones con llaves ${...} son el mecanismo principal para acceder a datos del modelo en Thymeleaf. Estas expresiones permiten obtener valores de variables, objetos y propiedades que el controlador ha enviado a la vista.

<!-- Acceso a variables simples -->
<p th:text="${mensaje}">Mensaje por defecto</p>
<p th:text="${precio}">0.00</p>

Para acceder a propiedades de objetos, utilizamos la notación de punto:

<!-- Acceso a propiedades de un objeto -->
<p th:text="${producto.nombre}">Nombre del producto</p>
<p th:text="${producto.precio}">Precio</p>
<p th:text="${cliente.email}">Email del cliente</p>

Las expresiones también permiten operaciones básicas y concatenación de texto:

<!-- Concatenación de texto -->
<p th:text="'El precio es: ' + ${producto.precio} + ' euros'">Precio</p>

<!-- Operaciones matemáticas -->
<p th:text="${cantidad * precio}">Total</p>

<!-- Acceso a elementos de listas por índice -->
<p th:text="${productos[0].nombre}">Primer producto</p>

Combinando atributos th: con expresiones

La verdadera potencia de Thymeleaf surge al combinar múltiples atributos th: en un mismo elemento:

<!-- Ejemplo completo combinando varios atributos -->
<div th:class="${activo} ? 'destacado' : 'normal'" 
     th:text="${producto.nombre}"
     th:title="${producto.descripcion}">
    Producto por defecto
</div>

Para formularios HTML, esta combinación es especialmente útil:

<form th:action="${'/productos/' + producto.id}" method="post">
    <input type="text" 
           th:value="${producto.nombre}" 
           th:placeholder="${'Introduce el nombre del producto'}"
           name="nombre">
    
    <button type="submit" th:text="${producto.id != null} ? 'Actualizar' : 'Crear'">
        Enviar
    </button>
</form>

Expresiones condicionales básicas

Dentro de las expresiones ${}, podemos utilizar operadores condicionales para tomar decisiones simples:

<!-- Operador ternario -->
<p th:text="${usuario.activo} ? 'Usuario activo' : 'Usuario inactivo'">Estado</p>

<!-- Verificación de nulidad -->
<p th:text="${producto.descuento != null} ? ${producto.descuento} + '%' : 'Sin descuento'">
    Descuento
</p>

<!-- Comparaciones numéricas -->
<span th:text="${stock > 0} ? 'Disponible' : 'Agotado'" 
      th:class="${stock > 0} ? 'disponible' : 'agotado'">
    Estado stock
</span>

Esta sintaxis básica de Thymeleaf proporciona las herramientas fundamentales para crear plantillas dinámicas. Los atributos th: permiten modificar cualquier aspecto del HTML, mientras que las expresiones ${} ofrecen acceso completo a los datos del modelo, creando una base sólida para construir interfaces web interactivas y dinámicas.

¿Te está gustando esta lección?

Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

Expresiones avanzadas *{}, @{} y #{}

Thymeleaf proporciona expresiones especializadas que van más allá de las básicas ${}, cada una diseñada para casos de uso específicos que mejoran la organización y funcionalidad de las plantillas.

Expresiones de selección *{}

Las expresiones de selección utilizan la sintaxis *{...} y están diseñadas para trabajar con un objeto específico como contexto. Estas expresiones son especialmente útiles cuando necesitamos acceder repetidamente a las propiedades de un mismo objeto.

Para establecer el objeto de contexto, utilizamos el atributo th:object:

<div th:object="${usuario}">
    <p th:text="*{nombre}">Nombre</p>
    <p th:text="*{email}">Email</p>
    <p th:text="*{telefono}">Teléfono</p>
</div>

Este enfoque es equivalente a escribir ${usuario.nombre}, ${usuario.email} y ${usuario.telefono}, pero resulta más limpio y mantenible cuando trabajamos intensivamente con un objeto.

En formularios, las expresiones de selección son particularmente valiosas:

<form th:object="${producto}" th:action="@{/productos}" method="post">
    <input type="text" th:field="*{nombre}" placeholder="Nombre del producto">
    <input type="number" th:field="*{precio}" placeholder="Precio">
    <textarea th:field="*{descripcion}" placeholder="Descripción"></textarea>
    <button type="submit">Guardar producto</button>
</form>

El atributo th:field combina automáticamente th:name, th:value y th:id, simplificando significativamente la creación de formularios vinculados a objetos.

Expresiones de enlace @{}

Las expresiones de enlace con sintaxis @{...} están especializadas en la construcción de URLs. Thymeleaf las procesa para generar rutas correctas considerando el contexto de la aplicación.

Para URLs básicas, las expresiones @{} aseguran que las rutas sean relativas al contexto de la aplicación:

<!-- Enlaces básicos -->
<a th:href="@{/productos}">Ver productos</a>
<a th:href="@{/usuarios/perfil}">Mi perfil</a>

<!-- Recursos estáticos -->
<link rel="stylesheet" th:href="@{/css/estilos.css}">
<script th:src="@{/js/aplicacion.js}"></script>

Para URLs con parámetros, podemos incluir variables directamente en la ruta:

<!-- Parámetros en la URL -->
<a th:href="@{/productos/{id}(id=${producto.id})}">Ver detalles</a>
<a th:href="@{/usuarios/{userId}/pedidos(userId=${usuario.id})}">Mis pedidos</a>

Los parámetros de consulta se especifican entre paréntesis:

<!-- Parámetros de consulta -->
<a th:href="@{/productos(categoria=${categoria},orden='precio')}">
    Productos por categoría
</a>

<!-- Resultado: /productos?categoria=electronica&orden=precio -->

También podemos combinar parámetros de ruta y consulta:

<a th:href="@{/productos/{cat}(cat=${categoria},pagina=${numeroPagina},tamaño=10)}">
    Página siguiente
</a>

<!-- Resultado: /productos/electronica?pagina=2&tamaño=10 -->

Expresiones de utilidad #{}

Las expresiones de utilidad #{...} proporcionan acceso a funciones auxiliares y mensajes de internacionalización. Estas expresiones son fundamentales para crear aplicaciones multiidioma y acceder a utilidades del sistema.

Para mensajes de internacionalización, las expresiones #{} buscan claves en archivos de propiedades:

<!-- Mensajes básicos -->
<h1 th:text="#{pagina.titulo}">Título por defecto</h1>
<p th:text="#{mensaje.bienvenida}">Mensaje de bienvenida</p>

Los mensajes pueden incluir parámetros dinámicos:

<!-- Mensaje con parámetros -->
<p th:text="#{usuario.saludo(${usuario.nombre})}">Saludo personalizado</p>

<!-- En messages.properties: usuario.saludo=Hola, {0}! Bienvenido -->

Las expresiones #{} también proporcionan acceso a objetos de utilidad como fechas, números y cadenas:

<!-- Formateo de fechas -->
<p th:text="${#dates.format(producto.fechaCreacion, 'dd/MM/yyyy')}">Fecha</p>

<!-- Formateo de números -->
<p th:text="${#numbers.formatDecimal(producto.precio, 1, 2)}">Precio formateado</p>

<!-- Utilidades de cadenas -->
<p th:text="${#strings.toUpperCase(producto.categoria)}">Categoría</p>

Combinando expresiones avanzadas

La verdadera potencia emerge al combinar diferentes tipos de expresiones en una misma plantilla:

<div th:object="${pedido}">
    <h2 th:text="#{pedido.titulo} + ' #' + *{numero}">Pedido</h2>
    
    <div th:each="item : *{items}">
        <a th:href="@{/productos/{id}(id=${item.producto.id})}"
           th:text="${item.producto.nombre}">
            Producto
        </a>
        <span th:text="${#numbers.formatCurrency(item.precio)}">Precio</span>
    </div>
    
    <p th:text="#{pedido.total} + ': ' + ${#numbers.formatCurrency(*{total})}">
        Total del pedido
    </p>
</div>

Este ejemplo muestra cómo las expresiones especializadas trabajan juntas: *{} para el contexto del objeto pedido, @{} para generar enlaces correctos, y #{} tanto para mensajes internacionalizados como para utilidades de formateo.

Las expresiones avanzadas de Thymeleaf proporcionan herramientas especializadas que simplifican tareas comunes en el desarrollo web, desde la gestión de formularios hasta la construcción de URLs y la internacionalización, manteniendo las plantillas organizadas y fáciles de mantener.

Estructuras de control en Thymeleaf

Las estructuras de control en Thymeleaf permiten implementar lógica condicional y repetitiva directamente en las plantillas HTML. Estas estructuras proporcionan la flexibilidad necesaria para crear interfaces dinámicas que se adapten a diferentes estados y conjuntos de datos.

Condicionales con th:if y th:unless

El atributo th:if evalúa una expresión y muestra el elemento únicamente cuando la condición es verdadera. Es la estructura condicional más básica y utilizada en Thymeleaf:

<!-- Mostrar elemento solo si hay productos -->
<div th:if="${productos != null and !productos.empty}">
    <h3>Productos disponibles</h3>
</div>

<!-- Mostrar mensaje para usuarios autenticados -->
<p th:if="${usuario != null}" th:text="'Bienvenido, ' + ${usuario.nombre}">
    Mensaje de bienvenida
</p>

El atributo th:unless funciona de manera opuesta a th:if, mostrando el elemento cuando la condición es falsa:

<!-- Mostrar mensaje cuando no hay productos -->
<p th:unless="${productos != null and !productos.empty}">
    No hay productos disponibles en este momento
</p>

<!-- Mostrar enlace de login para usuarios no autenticados -->
<a th:unless="${usuario != null}" th:href="@{/login}">Iniciar sesión</a>

Las condiciones complejas pueden combinarse utilizando operadores lógicos:

<!-- Múltiples condiciones -->
<div th:if="${usuario != null and usuario.activo and usuario.rol == 'ADMIN'}">
    <button th:text="#{admin.panel}">Panel de administración</button>
</div>

<!-- Verificación de rangos numéricos -->
<span th:if="${producto.stock > 0 and producto.stock <= 5}" 
      class="stock-bajo">
    ¡Últimas unidades!
</span>

Condicionales múltiples con th:switch

Para múltiples condiciones mutuamente excluyentes, th:switch proporciona una alternativa más limpia que múltiples th:if:

<div th:switch="${usuario.rol}">
    <p th:case="'ADMIN'" th:text="#{mensaje.admin}">Panel de administrador</p>
    <p th:case="'MODERADOR'" th:text="#{mensaje.moderador}">Panel de moderador</p>
    <p th:case="'USUARIO'" th:text="#{mensaje.usuario}">Panel de usuario</p>
    <p th:case="*" th:text="#{mensaje.invitado}">Acceso como invitado</p>
</div>

El caso por defecto se especifica con th:case="*" y se ejecuta cuando ninguna otra condición coincide:

<div th:switch="${pedido.estado}">
    <span th:case="'PENDIENTE'" class="estado-pendiente">Procesando pedido</span>
    <span th:case="'ENVIADO'" class="estado-enviado">En camino</span>
    <span th:case="'ENTREGADO'" class="estado-entregado">Entregado</span>
    <span th:case="*" class="estado-desconocido">Estado no disponible</span>
</div>

Iteraciones con th:each

El atributo th:each permite iterar sobre colecciones, arrays y mapas, generando elementos HTML de forma dinámica:

<!-- Iteración básica sobre una lista -->
<ul>
    <li th:each="producto : ${productos}" th:text="${producto.nombre}">
        Nombre del producto
    </li>
</ul>

Durante la iteración, Thymeleaf proporciona variables de estado que contienen información útil sobre el proceso:

<table>
    <tr th:each="usuario, estado : ${usuarios}">
        <td th:text="${estado.index + 1}">Número</td>
        <td th:text="${usuario.nombre}">Nombre</td>
        <td th:text="${usuario.email}">Email</td>
        <td th:if="${estado.odd}" class="fila-impar">Fila impar</td>
        <td th:if="${estado.even}" class="fila-par">Fila par</td>
    </tr>
</table>

Las variables de estado más útiles incluyen:

  • index: índice actual (comenzando en 0)
  • count: contador actual (comenzando en 1)
  • size: tamaño total de la colección
  • odd/even: indica si la iteración actual es impar o par
  • first/last: indica si es el primer o último elemento
<div th:each="categoria, info : ${categorias}">
    <h3 th:text="${categoria.nombre}">Categoría</h3>
    
    <!-- Mostrar separador excepto en el último elemento -->
    <hr th:unless="${info.last}">
    
    <!-- Mostrar información de progreso -->
    <small th:text="'Elemento ' + ${info.count} + ' de ' + ${info.size}">
        Progreso
    </small>
</div>

Iteraciones con condiciones

Las estructuras de control pueden combinarse para crear lógica más sofisticada:

<!-- Iterar solo sobre productos activos -->
<div th:each="producto : ${productos}" th:if="${producto.activo}">
    <h4 th:text="${producto.nombre}">Producto</h4>
    <p th:text="${producto.descripcion}">Descripción</p>
    
    <!-- Mostrar descuento si existe -->
    <span th:if="${producto.descuento != null}" 
          th:text="'Descuento: ' + ${producto.descuento} + '%'"
          class="descuento">
        Descuento
    </span>
</div>

Para listas anidadas, podemos combinar múltiples th:each:

<div th:each="categoria : ${categorias}">
    <h2 th:text="${categoria.nombre}">Categoría</h2>
    
    <div th:if="${categoria.productos != null and !categoria.productos.empty}">
        <div th:each="producto : ${categoria.productos}">
            <p th:text="${producto.nombre}">Producto</p>
            <span th:text="${producto.precio} + ' €'">Precio</span>
        </div>
    </div>
    
    <p th:unless="${categoria.productos != null and !categoria.productos.empty}">
        No hay productos en esta categoría
    </p>
</div>

Estructuras de control en formularios

Las estructuras de control son especialmente útiles en formularios dinámicos:

<form th:object="${formularioContacto}" th:action="@{/contacto}" method="post">
    
    <!-- Campo condicional según el tipo de consulta -->
    <div th:if="*{tipoConsulta == 'COMERCIAL'}">
        <label>Empresa:</label>
        <input type="text" th:field="*{empresa}">
    </div>
    
    <!-- Lista dinámica de opciones -->
    <select th:field="*{categoria}">
        <option value="">Selecciona una categoría</option>
        <option th:each="cat : ${categorias}" 
                th:value="${cat.id}" 
                th:text="${cat.nombre}">
            Categoría
        </option>
    </select>
    
    <button type="submit">Enviar consulta</button>
</form>

Las estructuras de control en Thymeleaf proporcionan la flexibilidad necesaria para crear plantillas que se adapten dinámicamente a los datos y el estado de la aplicación, manteniendo la separación entre lógica de presentación y lógica de negocio.

Aprendizajes de esta lección

  • Comprender la sintaxis básica de Thymeleaf y el uso de atributos th: para modificar elementos HTML.
  • Aprender a utilizar expresiones básicas ${} para acceder a datos del modelo y realizar operaciones simples.
  • Conocer las expresiones avanzadas *{}, @{} y #{} para manejo de objetos, URLs e internacionalización.
  • Implementar estructuras de control como condicionales (th:if, th:unless, th:switch) e iteraciones (th:each) en plantillas.
  • Aplicar las estructuras de control y expresiones en formularios dinámicos para interfaces web interactivas.

Completa SpringBoot y certifícate

Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.

Asistente IA

Resuelve dudas al instante

Ejercicios

Practica con proyectos reales

Certificados

Valida tus conocimientos

Más de 25.000 desarrolladores ya se han certificado con CertiDevs

⭐⭐⭐⭐⭐
4.9/5 valoración