Search buenodc

Nesta página
  1. Expressões de variáveis
  2. Expressões de seleção
  3. Expressões de mensagens
  4. Expressões de links
  5. Expressões de fragmentos

Dialetos do Thymeleaf

O Thymeleaf é uma engine de templates que permite a criação de páginas HTML dinâmicas e usa o conceito chamado de dialetos para adicionar recursos específicos ao HTML. Você consegue identificar um dialeto quando vê um atributo HTML que começa com th:. Por exemplo, o atributo th:text é um dialeto que permite a exibição de dados dinâmicos na página HTML.

Os dialetos do Thymeleaf permitem que receber valores chamados de expressões e são classificadas em 5 tipos:

  • ${...}: Expressões de variáveis
  • *{...}: Expressões de seleção
  • #{...}: Expressões de mensagens (internacionalização)
  • @{...}: Expressões de links (URLs)
  • ~{...}: Expressões de fragmentos

Expressões de variáveis

As expressões de variáveis são usadas para exibir valores dinâmicos na página HTML. Por exemplo, se você tem uma variável chamada nome e quer exibir o seu valor na página HTML, você pode usar a expressão ${nome} dentro do dialeto th:text. O resultado final ficaria

<p th:text="${nome}">Nome</p>

Expressões de seleção

As expressões de seleção são como as expressões de variáveis, mas são usadas para selecionar um atributo de um objeto. O objeto em que as expressões de seleção são aplicadas são aqueles definidos pelo dialeto th:object. Por exemplo, se você tem um objeto chamado produto e quer exibir o seu atributo nome na página HTML, você pode usar a expressão *{nome} dentro do dialeto th:text assim que tiver mapeado o objeto produto com o dialeto th:object. O resultado final ficaria

<div th:object=${produto}>
    <p th:text="*{nome}"></p>
</div>

Expressões de mensagens

São utilizadas para exibir mensagens geralmente chamadas de externalização de texto, internacionalização ou i18n. Elas permitem acessar um arquivo de propriedades que contém as mensagens e exibi-las na página HTML. Por exemplo, se você tem um arquivo de propriedades chamado messages.properties e quer exibir a mensagem site.welcome na página HTML, você pode usar a expressão #{site.welcome} dentro do dialeto th:text. O resultado final ficaria

<p th:text="#{site.welcome}">Hello</p>

O arquivo de propriedades deve estar na pasta src/main/resources e deve ter a extensão .properties. Para saber mais sobre arquivos de propriedades, acesse este link.

São utilizados para construir URLs de acordo com o contexto que está sendo executado. Podem ser de diferentes tipos: absolutos, relativos, contextuais, etc. Por exemplo, se você quer construir uma URL para a página index.html, você pode usar a expressão @{/index.html} dentro do dialeto th:href. O resultado final ficaria

<a th:href="@{/index.html}">Home</a>

Expressões de fragmentos

Os fragmentos permitem a movimentação de pedaços de código HTML em diferentes páginas. Através deles é possível reaproveitar o código, usar o código HTML como argumento de outra tag HTML e até mesmo passar parâmetros para o fragmento.

Por exemplo, imagine que você tem uma página que contém um rodapé e quer reaproveitá-lo em outras páginas, ou seja, você quer separar esse trecho de marcação (HTML) em um arquivo separado e incluí-lo em outras páginas.

Você pode criar um arquivo chamado rodape.html e colocar o código HTML do rodapé dentro dele. Depois, você pode incluir esse arquivo em outras páginas usando a expressão ~{rodape} dentro do dialeto th:insert. O resultado final ficaria

<div th:insert="~{rodape}"></div>

A sintaxe das expressões de fragmento podem ter três diferentes formas:

  • ~{nome-do-arquivo}: Inclui o arquivo inteiro.
  • ~{nome-do-arquivo :: nome-do-fragmento}: Inclui apenas o fragmento do arquivo especificado no arquivo de template. Logo, o arquivo de template deve ter um fragmento th:fragment com o nome especificado.
  • ~{::nome-do-fragmento}: Insere o fragmento do arquivo de template atual. Ou seja, o arquivo de template deve ter um fragmento th:fragment com o nome especificado.

Ainda é possível incluir fragmentos que não fazem uso do atributo th:fragment. Para isso, você deve referenciar o trecho de código que deseja incluir utilizando o atributo id da marcação HTML.

<div id="rodape">
    <p>Este é o rodapé</p>
</div>

Depois, você pode incluir esse trecho de código em outra página usando a expressão ~{#rodape} dentro do dialeto th:insert. O resultado final ficaria

<div th:insert="~{footer :: #rodape}"></div>

É importante compreender também a diferença entre os dialetos th:insert e th:replace. Os nomes tentam deixar bastante claro a diferença entre eles em que o insert faz a inserção do código HTML no local especificado e o replace faz a substituição do código HTML no local especificado. O exemplo abaixo ilustra bem a diferença entre eles.

<footer th:fragment="rodape">
    <p>Este é o rodapé</p>
</footer>
<body>
    <div th:insert="~{footer :: rodape}"></div>
    <div th:replace="~{footer :: rodape}"></div>
</body>

O resultado final ficaria

<body>
    <div>
        <footer>
            <p>Este é o rodapé</p>
        </footer>
    </div>
    <footer>
        <p>Este é o rodapé</p>
    </footer>
</body>

Veja que o dialeto th:insert inclui o código HTML dentro da tag div e o dialeto th:replace substitui o código HTML da tag div pelo código HTML do rodapé.

Herança de Layout

A herança de layout é um recurso que permite a criação de um template base que pode ser herdado por outros templates. Por exemplo, você pode criar uma página chamada app.html e colocar o código HTML que se repete em todas as páginas dentro dela. Depois, você pode criar outros páginas que herdam o template base e incluir o código HTML específico de cada página.

Vamos usar a página home.html como layout base. Para isso precisamos definir a tag html como sendo um fragmento e que receberá parâmetros para que possamos herdar esse layout em outros arquivos. O resultado final ficaria

<!DOCTYPE html>
<html lang="pt-br" th:fragment="layout(content)">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/css/pico.min.css">
    <title>Home</title>
</head>
<body class="container">
    <main th:replace="${content}"></main>
</body>
</html>

O importante no código é o atributo th:fragment que define o nome do fragmento e o parâmetro content que será usado para receber o conteúdo das outras páginas. Perceba que logo mais abaixo o parâmetro content é usado para substituir o conteúdo da tag main através do dialeto th:replace. Ou seja, o conteúdo recebido por parâmetro será substituído no local onde o parâmetro ${content} está sendo declarado.

Agora que temos um template base, podemos criar outras páginas que herdam esse template. Vamos aproveitar a página de listar usuários user/list.html. O resultado final ficaria

<html th:replace="~{home :: layout(~{::body})}">
<body>
    <h1>Users</h1>
    <table>
        <tr>
            <th>ID</th>
            <th>Email</th>
            <th>Actions</th>
        </tr>
        <tr th:each="user : ${users}">
            <td th:text="${user.id}"></td>
            <td th:text="${user.email}"></td>
            <td>
                <a th:href="@{/users/show(id = ${user.id})}">Show</a> | 
                <a th:href="@{/users/edit(id = ${user.id})}">Edit</a> | 
                <a th:href="@{/users/delete(id = ${user.id})}">Delete</a>
            </td>
        </tr>
    </table>
    <a th:href="@{/users/create}">New user</a>
</body>
</html>

Perceba que omitimos diversas tags HTML pois elas já estão declaradas no template base. Agora é necessário herdar o template base, para isso utiliza-se o dialeto th:replace com o valor ~{home :: layout(~{::body})}. Aonde, home é o nome do arquivo que contém o template base e layout(..) é o nome da função declarada no template base, e ~{::body} é valor que sera passado como parâmetro para a função layout(..), e nesse caso representa o seletor de tag body da página em questão. Ou seja, o conteúdo do body da página list.html será substituído no local onde o parâmetro ${content} está sendo declarado no template base.

Você pode replicar o mesmo conceito para as páginas create, edit e show para praticar.