Thymeleaf: descubra como usá-lo em aplicações Java

Thymeleaf: descubra como usá-lo em aplicações Java
Armano Barros Alves Junior
Armano Barros Alves Junior

Compartilhe

Se você é uma pessoa desenvolvedora Java ou se aventura nessa tecnologia, provavelmente já ouviu falar sobre o Thymeleaf, motor de templates que permite integrar a lógica do servidor diretamente no código HTML.

Isso porque no mundo de desenvolvimento web, a escolha das ferramentas faz toda a diferença na qualidade do produto final.

Neste artigo, mergulharemos no universo do Thymeleaf com Spring Framework, explorando como a combinação pode elevar o nível dos seus projetos web.

Abordaremos desde conceitos fundamentais até a implementação prática, passando por comparações com outras tecnologias e destacando as vantagens dessa abordagem.

Além disso, guiaremos você pelos primeiros passos para criar e executar uma aplicação com páginas dinâmicas, usando o Thymeleaf para processar dados na tela.

O que é Thymeleaf e como funciona?

O Thymeleaf é um motor de templates moderno e versátil para Java, projetado para ser utilizado tanto em ambientes web quanto em ambientes que não sejam web.

Em ambientes web, ele é comumente usado para gerar páginas HTML dinâmicas, atualizadas em tempo real, nas quais adicionamos valores e informações vindas do banco de dados. Por exemplo:

<table>
  <thead>
    <tr>
      <th>Nome</th>
      <th>Preço</th>
    </tr>
  </thead>
  <tbody>
    <tr th:each="produto : ${produtos}">
      <td th:text="${produto.nome}">Nome do Produto</td>
      <td th:text="${#numbers.formatDecimal(produto.preco, 1, 2)}">0.00</td>
    </tr>
  </tbody>
</table>

Neste exemplo, o Thymeleaf itera sobre uma lista de produtos que poderiam estar listados numa página como a de um e-commerce e gera uma tabela HTML dinâmica, formatando o preço adequadamente.

Nos demais ambientes, o Thymeleaf pode ser utilizado para gerar documentos como PDFs, relatórios, ou e-mails em formato HTML. Um exemplo de uso para gerar um PDF baseado em HTML seria:

Context context = new Context();
context.setVariable("cliente", cliente);
context.setVariable("pedido", pedido);

String htmlContent = templateEngine.process("template-pedido", context);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(htmlContent);
renderer.layout();
renderer.createPDF(outputStream);

// Enviar o PDF gerado como resposta ou salvar em arquivo

No exemplo acima, o Thymeleaf processa uma página HTML, "template-pedido" e carrega as informações do pedido realizado, então uma biblioteca como o Flying Saucer é usada para converter o HTML em PDF.

Isso é útil para gerar relatórios personalizados, faturas ou qualquer documento com flexibilidade do HTML combinada com a portabilidade do PDF.

Ele se destaca pela abordagem de "templates naturais", o que significa que os templates Thymeleaf são arquivos HTML válidos, que podem ser visualizados diretamente em um navegador, mesmo sem serem processados pelo servidor.

Banner promocional da Alura, com um design futurista em tons de azul, apresentando dois blocos de texto, no qual o bloco esquerdo tem os dizeres:

Funcionamento e sintaxe do Thymeleaf

Ele funciona como uma interligação entre o código Java e as páginas HTML da aplicação, substituindo as expressões e atributos especiais por valores dinâmicos antes de enviar o HTML resultante para o cliente.

Imagem com 3 células. O título da primeira delas é Client e lemos o texto “Cliente de software envia uma requisição”. Há uma seta apontando para a segunda, com o título Server, na qual há o texto “Controlador fornece a view para o cliente”. Uma seta aponta para a terceira, com o título View e o texto “Template do Thymeleaf exibe as informações”.

A sintaxe do Thymeleaf são dialetos usados em atributos do HTML e geralmente tem o prefixo "th", como no código abaixo :

<span th:text="${mensagem}">Texto padrão</span>

Neste caso, ${mensagem} será substituído pelo valor da variável de mensagem definida no controlador Java. Outro recurso é a capacidade de usar diferentes tipos de expressões para formatar o código. Acompanhe quais podemos usar.

Exibir uma variável

Se você precisar mostrar uma variável na tela, como um nome, pode usar uma sintaxe na qual o valor da propriedade nome do objeto usuario será exibido na página. Veja a seguir:

<p th:text="${usuario.nome}">Nome do usuário</p>

Seleção condicional

Se você precisar fazer uma seleção para exibir determinado conteúdo apenas se uma condição for verdadeira, pode usar uma sintaxe na qual o conteúdo dentro da div será exibido apenas se o atributo admin do objeto usuario for verdadeiro:

<div th:if="${usuario.admin}">
  <p>Conteúdo visível apenas para administradores</p>
</div>

Expressões de URL

Para gerar URLs dinâmicas na sua aplicação, essa é a sintaxe que você deve utilizar:

<a th:href="@{/caminho/do/recurso}">Link</a>

Iteração com th:each

Se você precisa exibir uma lista de itens, você pode usar a diretiva th:each para iterar sobre a lista:

<ul>
  <li th:each="item : ${itens}" th:text="${item.nome}">Nome do item</li>
</ul>

Qual a diferença entre o Thymeleaf e o JSP?

Uma alternativa ao Thymeleaf bastante conhecida é o JSP (JavaServer Pages), que também permite integrar lógica de servidor com o código HTML. No entanto, existem diferenças significativas entre as duas abordagens.

O JSP utiliza uma mistura de HTML e código Java diretamente em uma mesma página, o que pode levar a uma mistura de responsabilidades entre a lógica de negócios e a apresentação, tornando o código menos legível e mais difícil de manter, especialmente em projetos de grande porte.

Imagine que você está desenvolvendo uma aplicação para um restaurante. Com JSP. Nesse caso, o código para exibir o cardápio poderia se parecer com o seguinte:

<%@ page import="java.util.List, com.restaurante.Prato" %>
<html>
<body>
    <h1>Cardápio</h1>
    <ul>
    <% 
    List<Prato> pratos = (List<Prato>)request.getAttribute("pratos");
    for(Prato prato : pratos) { 
    %>
        <li><%= prato.getNome() %> - R$ <%= String.format("%.2f", prato.getPreco()) %></li>
    <% } %>
    </ul>
</body>
</html>

Neste exemplo há uma mistura de HTML, Java e expressões JSP, o que pode tornar o código difícil de ler e manter, especialmente para devs que não tem familiaridade com Java.

Por outro lado, o Thymeleaf adota uma abordagem mais organizada e semântica usando HTML válido.

Assim as pessoas desenvolvedoras podem focar na construção da interface da página, enquanto o mecanismo de templates cuida da integração com a lógica do back-end.

O mesmo exemplo usando Thymeleaf ficaria assim:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
    <h1>Cardápio</h1>
    <ul>
        <li th:each="prato : ${pratos}">
            <span th:text="${prato.nome}">Nome do Prato</span> - 
            R$ <span th:text="${#numbers.formatDecimal(prato.preco, 1, 2)}">0.00</span>
        </li>
    </ul>
</body>
</html>

Vantagens do uso do Thymeleaf

Já falamos bastante sobre o Thymeleaf e suas características, mas o que ganhamos ao utilizá-lo nos nossos projetos?

  • Tudo no seu devido lugar: A lógica de negócios fica só com o controlador, e o template? Fica por conta do Thymeleaf. Assim, cada parte do código faz o seu trabalho.

  • HTML válido: O template é um HTML 100% válido, que você pode abrir direto no navegador. Isso facilita a vida de devs e designers na hora de colaborar.

  • Visual limpo: As expressões do Thymeleaf são super limpas e se misturam bem com o HTML, tornando tanto a legibilidade quanto a manutenção mais simplificadas.

Essas características tornam o Thymeleaf uma escolha mais robusta e flexível para projetos modernos de desenvolvimento web, especialmente quando comparado ao JSP.

Porém, a escolha entre um ou outro dependerá das necessidades específicas de cada projeto e de possíveis condições e restrições da equipe de desenvolvimento envolvida.

Atualmente no mercado o Thymeleaf tem sido uma opção atraente, já que consegue equilibrar eficientemente código limpo e responsabilidade única. Enquanto isso, o JSP pode ser mais familiar para projetos legados.

Seu primeiro projeto Spring com Thymeleaf

Agora que você já sabe o que é o Thymeleaf e como ele funciona, vamos colocar a mão na massa.

O foco do projeto será desenvolver uma aplicação web que realize o cadastro de filmes, havendo uma página responsável por fazer esse cadastro e outra para mostrar os filmes já cadastrados.

No final desta seção, teremos um projeto similar ao da imagem abaixo:

Imagem de uma planilha com fundo azul e o título “Lista de filmes”. Abaixo do título, ao centro, há um botão "Novo". Há quatro colunas, sendo elas: Nome, Duração, Ano Lançamento e Gênero. Em Nome, há dois filmes listados, "Homem Aranha" e "Vingadores, sendo as durações 120 e 130 e os anos, 2018 e 2018, respectivamente. Ambos trazem “Ação” em “Gênero”".

Vamos lá?

Iniciando o projeto

Como de costume, para iniciarmos um projeto Spring usaremos o Spring Initializr. Nele selecionaremos o [Maven] como o gerenciador de dependências do projeto, o Java como linguagem de programação e a versão 3.3.3 (atual LTS do Spring).

Além disso, devemos adicionar duas dependências, sendo elas Thymeleaf, a que carregará todo o necessário para usar o Thymeleaf no projeto, e Spring Web, para criamos Endpoints que chamarão os Templates criados usando o Thymeleaf.

Nos demais campos da seção "Project Metadata", você poderá preencher da forma que preferir. Segue uma captura de tela

Recorte do ambiente de inicialização de um projeto Spring, com sessões para selecionar o gerenciador do projeto, linguagem, versão e metadados.

Por fim, precisaremos clicar na opção "GENERATE", que está no canto inferior central ou pressionar as teclas "CTRL + ENTER", gerando assim um arquivo compactado com toda a estrutura do projeto. Bastará descompactá-lo.

Criação das rotas e modelo de dados

Agora, com o projeto base em mãos, primeiro precisaremos abri-lo no IntelliJ ou na sua IDE de preferência.

No arquivo principal do projeto Spring, criaremos dois novos packages, um chamado "controller" e outro "model". No controller deixaremos a parte de lógica de acesso ao template e no model a representação das informações que são mostradas.

Começando pelo package controller, criaremos uma classe chamada FilmeController que conterá:

  1. Uma lista que armazenará as informações sobre os filmes:
   private List<Filme> filmes = new ArrayList<>();
  1. Uma rota para carregar o template do formulário de cadastro de filmes:
    @GetMapping("/formulario")
    public String carregaPaginaFormulario() {
        return "formulario";
    }
  1. Uma rota para carregar o template de listagem dos filmes cadastrados:
    @GetMapping
    public String carregaPaginaListagem(Model model) {
        model.addAttribute("lista", filmes);
        return "listagem";
    }
  1. Uma rota para cadastrar os filmes na lista que criamos anteriormente:
    @PostMapping
    public String cadastraFilme(DadosCadastroFilme dados) {
        var filme = new Filme(dados);
        filmes.add(filme);

        return "redirect:/filmes";
    }

No package model, teremos a classe, Filme que posteriormente, será o objeto adicionado na lista filmes e o record DadosCadastroFilmes, que é o DTO usado no cadastro dos filmes.

Código de Filme:

package br.com.alura.filmeteca.model;

public class Filme {

    private String nome;
    private Integer duracaoEmMinutos;
    private Integer anoLancamento;
    private String genero;

    public Filme(DadosCadastroFilme dados) {
        this.nome = dados.nome();
        this.duracaoEmMinutos = dados.duracao();
        this.anoLancamento = dados.ano();
        this.genero = dados.genero();
    }

    @Override
    public String toString() {
        return "Filme{" +
                "nome='" + nome + '\'' +
                ", duracaoEmMinutos=" + duracaoEmMinutos +
                ", anoLancamento=" + anoLancamento +
                ", genero='" + genero + '\'' +
                '}';
    }

    public String getNome() {
        return nome;
    }

    public Integer getDuracaoEmMinutos() {
        return duracaoEmMinutos;
    }

    public Integer getAnoLancamento() {
        return anoLancamento;
    }

    public String getGenero() {
        return genero;
    }
}

Código de DadosCadastroFilme:

package br.com.alura.filmeteca.model;

public record DadosCadastroFilme(String nome, Integer duracao, Integer ano, String genero) {}

Desenvolvimento das páginas HTML com Thymeleaf

Agora vamos trabalhar nos templates. Acesse o caminho "src>main>resources" e na pasta "templates", crie dois arquivos HTML, com os nomes de formulario e listagem.

Ao criar arquivos HTML no IntelliJ ele já trará uma estrutura básica HTML. Então, os próximos passos serão descritos a partir desta estrutura pré-existente.

Exemplo de estrutura base:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
</html>

Para a estilização das páginas, você pode copiar código css e criar uma pasta "static". Dentro da pasta, será necessário criar um arquivo css com o nome "estilos.css".

Começando com a página formulario como propriedade da tag <html>, faremos a importação da biblioteca do Thymeleaf e vamos carregá-la para uma variável que, por padrão, é chamada de th:

<html lang="en"
      xmlns:th="http://thymeleaf.org">

Para essa página, o Thymeleaf será responsável apenas por importar o arquivo "estilos.css". Então, dentro da tag <head>, adicione a seguinte importação:

    <link rel="stylesheet" href="../static/estilos.css" th:href="@{/estilos.css}">
    <title>Listagem de filmes</title>

Agora, dentro da tag <body> adicionaremos uma <div> que conterá o nosso formulário do cadastro de filmes.

Nas propriedades da tag <form> teremos o method="post" dizendo que tipo de método HTTP será executado, e o action="/filmes", no qual /filmes representa a rota do controlador cadastraFilme.

<div>
    <h1>Cadastro de filme</h1>
    <form method="post" action="/filmes">
        <label for="nome">Nome:</label>
        <input id="nome" name="nome">

        <br/>

        <label for="duracao">Duração (em minutos):</label>
        <input id="duracao" name="duracao">

        <br/>

        <label for="ano">Ano de lançamento:</label>
        <input id="ano" name="ano">

        <br/>

        <label for="genero">Gênero:</label>
        <input id="genero" name="genero">

        <br/>

        <input type="submit" value="Cadastrar">
    </form>
</div>

Por fim, vamos configurar a página listagem. Como o foco do artigo não é a construção HTML, mas sim a utilização do Thymeleaf, deixaremos a implementação do formulário abaixo e explicaremos a estrutura do Thymeleaf.

Lembrando que para essa página, é necessário importar o Thymeleaf e o arquivo "estilo.css", assim como foi feito na página anterior.

<div>
    <h1>Lista de filmes</h1>

    <a href="/filmes/formulario">Novo</a>

    <table>
        <thead>
        <tr>
            <th>NOME</th>
            <th>DURAÇÃO</th>
            <th>ANO LANÇAMENTO</th>
            <th>GÊNERO</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="filme : ${lista}">
            <td th:text="${filme.nome}"></td>
            <td th:text="${filme.duracaoEmMinutos}"></td>
            <td th:text="${filme.anoLancamento}"></td>
            <td th:text="${filme.genero}"></td>
        </tr>
        </tbody>
    </table>
</div>

O Thymeleaf entra em ação na parte do corpo da tabela <tbody>. Aqui, vemos uma linha <tr> com um atributo especial f: th:each="filme:${lista}".

Este atributo é como uma instrução para o Thymeleaf: "Para cada filme na lista de filmes, crie uma nova linha na tabela".

A variável ${lista} contém todos os filmes que já foram cadastrados a ser mostrados, logo, será percorrida toda essa lista, criando uma linha para cada filme nela.

Dentro de cada linha, temos quatro células <td>, cada uma com seu próprio atributo th:text.

Por exemplo, th:text="${filme.nome}" diz ao Thymeleaf para inserir o nome do filme atual naquela célula. O mesmo acontece para a duração, ano de lançamento e gênero.

Dessa forma, o Thymeleaf automatiza o preenchimento da tabela com os dados de cada filme, em vez de ser necessário adicionar manualmente à página.

Caso tenha ficado em dúvida sobre algum passo da implementação, não se preocupe, acesse o projeto completo deste artigo.

Conclusão

Como vimos neste artigo, o Thymeleaf é uma ferramenta que oferece uma abordagem simples, fácil de usar e que possibilita a criação de páginas dinâmicas.

Como ele tem uma estrutura simples e se integra facilmente com o Spring Framework, as pessoas desenvolvedoras que trabalham com Thymeleaf podem focar na construção de interfaces web, o que otimiza o processo de desenvolvimento.

Ele também incentiva que o código seja limpo e bem organizado, pois permite que o código HTML seja válido tanto no servidor quanto no cliente. Assim não é necessário misturar lógicas complexas ou linguagens diferentes

Se você busca uma solução flexível para estruturar suas páginas HTML no Java, o Thymeleaf é uma opção altamente recomendável.

E aí? Gostou dessa tecnologia? Se você está mergulhando no desenvolvimento Java e quer conhecer ainda mais sobre Thymeleaf, confira esses conteúdos que separamos para você:

Abraços e até a próxima!

Armano Barros Alves Junior
Armano Barros Alves Junior

Um amante de tecnologia, leitura e da cultura geek, atualmente cursando Ciência da Computação na Universidade Federal do Tocantins. Faço parte do time do Suporte Educacional aqui na Alura.

Veja outros artigos sobre Programação