0% acharam este documento útil (0 voto)
439 visualizações34 páginas

Tutorial - Thymeleaf + Spring

Este documento fornece um tutorial sobre como integrar o Thymeleaf com o framework Spring. Ele explica como configurar o dialeto SpringStandard para permitir o uso do Spring Expression Language em modelos Thymeleaf e fornecer recursos adicionais de integração. Também discute como configurar resolvedores e motores de modelo Thymeleaf para trabalhar com recursos e mensagens Spring.

Enviado por

rolipam
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
439 visualizações34 páginas

Tutorial - Thymeleaf + Spring

Este documento fornece um tutorial sobre como integrar o Thymeleaf com o framework Spring. Ele explica como configurar o dialeto SpringStandard para permitir o uso do Spring Expression Language em modelos Thymeleaf e fornecer recursos adicionais de integração. Também discute como configurar resolvedores e motores de modelo Thymeleaf para trabalhar com recursos e mensagens Spring.

Enviado por

rolipam
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd

01/08/2020 Tutorial: Thymeleaf + Spring

Thymeleaf

Tutorial: Thymeleaf + Spring


Versão do documento: 20181029 - 29 outubro 2018
Versão do projeto: [Link]
Site do projeto: [Link]

[Link] 1/34
01/08/2020 Tutorial: Thymeleaf + Spring

Prefácio
Este tutorial explica como o Thymeleaf pode ser integrado ao Spring Framework, especialmente (mas não apenas) o Spring
MVC.

Observe que o Thymeleaf possui integrações para as versões [Link] 4.x do Spring Framework, fornecidas por duas bibliotecas
separadas chamadas thymeleaf-spring3 e thymeleaf-spring4 . Essas bibliotecas são empacotadas em .jar arquivos
separados ( thymeleaf-spring3-{version}.jar e thymeleaf-spring4-{version}.jar ) e precisam ser adicionadas ao seu
caminho de classe para usar as integrações do Thymeleaf Spring em seu aplicativo.

As amostras de código e o exemplo de aplicativo neste tutorial usam o Spring [Link] suas integrações Thymeleaf
correspondentes, mas o conteúdo deste texto também é válido para o Spring 3.x. Se seu aplicativo usa o Spring 3.x, tudo o
que você precisa fazer é substituir o [Link].spring4 pacote [Link].spring3 nos exemplos de código.

[Link] 2/34
01/08/2020 Tutorial: Thymeleaf + Spring

1 Integrando Thymeleaf com Spring


O Thymeleaf oferece um conjunto de integrações do Spring que permitem usá-lo como um substituto completo para JSP em
aplicativos Spring MVC.

Essas integrações permitem:

Faça com que os métodos mapeados nos @Controller objetos do Spring MVC sejam encaminhados para os modelos
gerenciados pelo Thymeleaf, exatamente como você faz com as JSPs.
Use Spring Expression Language (Spring EL) em vez de OGNL em seus modelos.
Crie formulários em seus modelos totalmente integrados aos seus beans de backup de formulários e ligações de
resultados, incluindo o uso de editores de propriedades, serviços de conversão e manipulação de erros de validação.
Exibir mensagens de internacionalização de arquivos de mensagens gerenciados pelo Spring (através dos
MessageSource objetos usuais ).
Resolva seus modelos usando os mecanismos de resolução de recursos do Spring.

Observe que, para entender completamente este tutorial, você deve primeiro ter lido o tutorial “Using Thymeleaf” , que
explica o Dialeto Padrão em profundidade.

[Link] 3/34
01/08/2020 Tutorial: Thymeleaf + Spring

2 O dialeto SpringStandard
Para alcançar uma integração mais fácil e melhor, o Thymeleaf fornece um dialeto que implementa especi camente todos os
recursos necessários para que ele funcione corretamente com o Spring.

Esse dialeto especí co é baseado no Thymeleaf Standard Dialect e é implementado em uma classe chamada
[Link] , que na verdade se estende de
[Link] .

Além de todos os recursos já presentes no Dialeto Padrão - e, portanto, herdados -, o SpringStandard Dialect apresenta os
seguintes recursos especí cos:

Use Spring Expression Language (Spring EL ou SpEL) como uma linguagem de expressão variável, em vez de OGNL.
Conseqüentemente, todas as expressões ${...} e *{...} serão avaliadas pelo mecanismo da linguagem de expressões
da Spring. Observe também que o suporte para o compilador Spring EL está disponível (Spring 4.2.4+).
Acesse quaisquer beans no contexto do aplicativo usando a sintaxe do SpringEL: ${@[Link]()}
New atributos para processamento de formulários: th:field , th:errors e th:errorclass , além de uma nova
implementação do th:object que permite que ele seja usado para seleção de comando formulário.
Um objeto e método de expressão #[Link](...) , que é equivalente à spring:theme tag customizada JSP.
Um objeto e método de expressão #[Link](...) , que é equivalente à spring:mvcUrl(...) função customizada JSP
(apenas no Spring 4.1+).

Observe que na maioria das vezes você não deve usar esse dialeto diretamente em um TemplateEngineobjeto normal como
parte de sua con guração. A menos que você tem necessidades muito especí cas de integração Spring, você deveria ser a
criação de uma instância de uma nova classe de motores modelo que executa todas as etapas de con guração necessárias
automaticamente [Link] .

Um exemplo de con guração de bean:

@Bean
public SpringResourceTemplateResolver templateResolver(){
// SpringResourceTemplateResolver automatically integrates with Spring's own
// resource resolution infrastructure, which is highly recommended.
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
[Link]([Link]);
[Link]("/WEB-INF/templates/");
[Link](".html");
// HTML is the default value, added here for the sake of clarity.
[Link]([Link]);
// Template cache is true by default. Set to false if you want
// templates to be automatically updated when modified.
[Link](true);
return templateResolver;
}

@Bean
public SpringTemplateEngine templateEngine(){
// SpringTemplateEngine automatically applies SpringStandardDialect and
// enables Spring's own MessageSource message resolution mechanisms.
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
[Link](templateResolver());
// Enabling the SpringEL compiler with Spring 4.2.4 or newer can
// speed up execution in most scenarios, but might be incompatible
// with specific cases when expressions in one template are reused
// across different data types, so this flag is "false" by default
// for safer backwards compatibility.
[Link](true);
return templateEngine;
}

Ou, usando a con guração baseada em XML do Spring:

[Link] 4/34
01/08/2020 Tutorial: Thymeleaf + Spring

<!-- SpringResourceTemplateResolver automatically integrates with Spring's own -->


<!-- resource resolution infrastructure, which is highly recommended. -->
<bean id="templateResolver"
class="[Link]">
<property name="prefix" value="/WEB-INF/templates/" />
<property name="suffix" value=".html" />
<!-- HTML is the default value, added here for the sake of clarity. -->
<property name="templateMode" value="HTML" />
<!-- Template cache is true by default. Set to false if you want -->
<!-- templates to be automatically updated when modified. -->
<property name="cacheable" value="true" />
</bean>

<!-- SpringTemplateEngine automatically applies SpringStandardDialect and -->


<!-- enables Spring's own MessageSource message resolution mechanisms. -->
<bean id="templateEngine"
class="[Link]">
<property name="templateResolver" ref="templateResolver" />
<!-- Enabling the SpringEL compiler with Spring 4.2.4 or newer can speed up -->
<!-- execution in most scenarios, but might be incompatible with specific -->
<!-- cases when expressions in one template are reused across different data -->
<!-- ypes, so this flag is "false" by default for safer backwards -->
<!-- compatibility. -->
<property name="enableSpringELCompiler" value="true" />
</bean>

[Link] 5/34
01/08/2020 Tutorial: Thymeleaf + Spring

3 visualizações e resolvedores de exibição

3.1 Exibições e exibições de resolvedores no Spring MVC

Existem duas interfaces no Spring MVC que estão em conformidade com o núcleo do seu sistema de modelos:

[Link]
[Link]

Visualiza as páginas de modelo em nossos aplicativos e nos permite modi car e prede nir seu comportamento, de nindo-os
como beans. As visualizações são responsáveis por renderizar a interface HTML real, geralmente pela execução de algum
mecanismo de modelo como o Thymeleaf.

ViewResolvers são os objetos encarregados de obter os objetos View para uma operação e localidade especí cas.
Normalmente, os controladores solicitam ao ViewResolvers que encaminhe para uma exibição com um nome especí co (uma
String retornada pelo método do controlador) e, em seguida, todos os resolvedores de exibição no aplicativo são executados
em cadeia ordenada até que um deles possa resolver essa exibição, na qual caso um objeto View seja retornado e o controle
seja passado para a renderização do HTML.

Observe que nem todas as páginas em nossos aplicativos precisam ser de nidas como Views, mas apenas aquelas cujo
comportamento desejamos não ser padrão ou con gurado de uma maneira especí ca (por exemplo, conectando
alguns beans especiais a ela). Se for solicitado a um ViewResolver uma exibição que não possua um bean
correspondente, que é o caso comum, um novo objeto View será criado ad hoc e retornado.

Uma con guração típica para um JSP + JSTL ViewResolver em um aplicativo Spring MVC do passado era assim:

<bean class="[Link]">
<property name="viewClass" value="[Link]" />
<property name="prefix" value="/WEB-INF/jsps/" />
<property name="suffix" value=".jsp" />
<property name="order" value="2" />
<property name="viewNames" value="*jsp" />
</bean>

Uma rápida olhada em suas propriedades é su ciente para saber como foi con gurada:

viewClass estabelece a classe das instâncias de exibição. Isso é necessário para um resolvedor JSP, mas não será
necessário quando estivermos trabalhando com o Thymeleaf.
prefix e suffix trabalhe de maneira semelhante aos atributos com os mesmos nomes nos objetos TemplateResolver do
Thymeleaf.
order estabelece a ordem em que o ViewResolver será consultado na cadeia.
viewNames permite a de nição (com caracteres curinga) dos nomes de exibição que serão resolvidos por este
ViewResolver.

3.2 Exibições e exibições de resolvedores no Thymeleaf

O Thymeleaf oferece implementações para as duas interfaces mencionadas acima:

[Link]
[Link]

Essas duas classes serão responsáveis pelo processamento dos modelos Thymeleaf como resultado da execução dos
controladores.

[Link] 6/34
01/08/2020 Tutorial: Thymeleaf + Spring

A con guração do Thymeleaf View Resolver é muito semelhante à do JSP:

@Bean
public ThymeleafViewResolver viewResolver(){
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
[Link](templateEngine());
// NOTE 'order' and 'viewNames' are optional
[Link](1);
[Link](new String[] {".html", ".xhtml"});
return viewResolver;
}

… Ou em XML:

<bean class="[Link]">
<property name="templateEngine" ref="templateEngine" />
<!-- NOTE 'order' and 'viewNames' are optional -->
<property name="order" value="1" />
<property name="viewNames" value="*.html,*.xhtml" />
</bean>

O templateEngine parâmetro é, obviamente, o SpringTemplateEngine objeto que de nimos no capítulo anterior. Os outros
dois ( order e viewNames ) são opcionais e têm o mesmo signi cado que no JSP ViewResolver que vimos anteriormente.

Observe que não precisamos prefix ou suffix parâmetros, porque eles já estão especi cados no Resolvedor de modelos
(que por sua vez é passado para o Mecanismo de modelos).

E se quiséssemos de nir um View bean e adicionar algumas variáveis estáticas? Fácil, basta de nir um protótipo de bean para
ele:

@Bean
@Scope("prototype")
public ThymeleafView mainView() {
ThymeleafView view = new ThymeleafView("main"); // templateName = 'main'
[Link](
[Link]("footer", "The ACME Fruit Company"));
return view;
}

Ao fazer isso, você poderá executar especi camente esse bean de exibição, selecionando-o pelo nome do bean ( mainView ,
neste caso).

[Link] 7/34
01/08/2020 Tutorial: Thymeleaf + Spring

Gerente de iniciação de sementes de tomilho de 4 molas


O código fonte dos exemplos mostrados neste e nos futuros capítulos deste guia pode ser encontrado no repositório do
GitHub do Spring Thyme Seed Starter Manager .

4.1 O Conceito

Na Thymeleaf, somos grandes fãs de tomilho, e toda primavera preparamos nossos kits de início de sementes com bom solo e
nossas sementes favoritas, colocamos sob o sol espanhol e esperamos pacientemente que nossas novas plantas cresçam.

Mas este ano nos cansamos de colar etiquetas nos contêineres iniciantes para saber qual semente estava em cada célula do
contêiner, então decidimos preparar um aplicativo usando o Spring MVC e o Thymeleaf para nos ajudar a catalogar nossos
iniciantes: The Spring Thyme SeedStarter Gerente .

Primeira página do STSM

De maneira semelhante ao aplicativo Good Thymes Virtual Grocery que desenvolvemos no tutorial Using Thymeleaf , o STSM
nos permitirá exempli car os aspectos mais importantes da integração do Thymeleaf como um mecanismo de modelo para o
Spring MVC.

[Link] 8/34
01/08/2020 Tutorial: Thymeleaf + Spring

4.2 Camada de negócios

Vamos precisar de uma camada de negócios muito simples para nossa aplicação. Primeiro de tudo, vamos dar uma olhada em
nossas entidades modelo:

Modelo STSM

Algumas classes de serviço muito simples fornecerão os métodos de negócios necessários. Gostar:

@Service
public class SeedStarterService {

@Autowired
private SeedStarterRepository seedstarterRepository;

public List<SeedStarter> findAll() {


return [Link]();
}

public void add(final SeedStarter seedStarter) {


[Link](seedStarter);
}

E:

@Service
public class VarietyService {

@Autowired
private VarietyRepository varietyRepository;

public List<Variety> findAll() {


return [Link]();
}

public Variety findById(final Integer id) {


return [Link](id);
}

}
[Link] 9/34
01/08/2020 Tutorial: Thymeleaf + Spring

4.3 Con guração do Spring MVC

Em seguida, precisamos de nir a con guração do Spring MVC para o aplicativo, que incluirá não apenas os artefatos padrão
do Spring MVC, como manipulação de recursos ou varredura de anotações, mas também a criação das instâncias do Template
Engine e do View Resolver.

@Configuration
@EnableWebMvc
@ComponentScan
public class SpringWebConfig
extends WebMvcConfigurerAdapter implements ApplicationContextAware {

private ApplicationContext applicationContext;

public SpringWebConfig() {
super();
}

public void setApplicationContext(final ApplicationContext applicationContext)


throws BeansException {
[Link] = applicationContext;
}

/* ******************************************************************* */
/* GENERAL CONFIGURATION ARTIFACTS */
/* Static Resources, i18n Messages, Formatters (Conversion Service) */
/* ******************************************************************* */

@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
[Link](registry);
[Link]("/images/**").addResourceLocations("/images/");
[Link]("/css/**").addResourceLocations("/css/");
[Link]("/js/**").addResourceLocations("/js/");
}

@Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
[Link]("Messages");
return messageSource;
}

@Override
public void addFormatters(final FormatterRegistry registry) {
[Link](registry);
[Link](varietyFormatter());
[Link](dateFormatter());
}

@Bean
public VarietyFormatter varietyFormatter() {
return new VarietyFormatter();
}

@Bean
public DateFormatter dateFormatter() {
return new DateFormatter();
}

[Link] 10/34
01/08/2020 Tutorial: Thymeleaf + Spring

/* **************************************************************** */
/* THYMELEAF-SPECIFIC ARTIFACTS */
/* TemplateResolver <- TemplateEngine <- ViewResolver */
/* **************************************************************** */

@Bean
public SpringResourceTemplateResolver templateResolver(){
// SpringResourceTemplateResolver automatically integrates with Spring's own
// resource resolution infrastructure, which is highly recommended.
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
[Link]([Link]);
[Link]("/WEB-INF/templates/");
[Link](".html");
// HTML is the default value, added here for the sake of clarity.
[Link]([Link]);
// Template cache is true by default. Set to false if you want
// templates to be automatically updated when modified.
[Link](true);
return templateResolver;
}

@Bean
public SpringTemplateEngine templateEngine(){
// SpringTemplateEngine automatically applies SpringStandardDialect and
// enables Spring's own MessageSource message resolution mechanisms.
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
[Link](templateResolver());
// Enabling the SpringEL compiler with Spring 4.2.4 or newer can
// speed up execution in most scenarios, but might be incompatible
// with specific cases when expressions in one template are reused
// across different data types, so this flag is "false" by default
// for safer backwards compatibility.
[Link](true);
return templateEngine;
}

@Bean
public ThymeleafViewResolver viewResolver(){
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
[Link](templateEngine());
return viewResolver;
}

4.4 O Controlador

Obviamente, também precisaremos de um controlador para nossa aplicação. Como o STSM conterá apenas uma página da
web com uma lista de iniciantes e um formulário para adicionar novos, escreveremos apenas uma classe de controlador para
todas as interações do servidor:

@Controller
public class SeedStarterMngController {

@Autowired
private VarietyService varietyService;

@Autowired
private SeedStarterService seedStarterService;

...

}
[Link] 11/34
01/08/2020 Tutorial: Thymeleaf + Spring

Agora vamos ver o que podemos adicionar a essa classe de controlador.

Atributos do modelo

Primeiro, adicionaremos alguns atributos de modelo que precisaremos na página:

@ModelAttribute("allTypes")
public List<Type> populateTypes() {
return [Link]([Link]);
}

@ModelAttribute("allFeatures")
public List<Feature> populateFeatures() {
return [Link]([Link]);
}

@ModelAttribute("allVarieties")
public List<Variety> populateVarieties() {
return [Link]();
}

@ModelAttribute("allSeedStarters")
public List<SeedStarter> populateSeedStarters() {
return [Link]();
}

Métodos mapeados

E agora a parte mais importante de um controlador, os métodos mapeados: um para mostrar a página do formulário e outro
para processar a adição de novos SeedStarter objetos.

@RequestMapping({"/","/seedstartermng"})
public String showSeedstarters(final SeedStarter seedStarter) {
[Link]([Link]().getTime());
return "seedstartermng";
}

@RequestMapping(value="/seedstartermng", params={"save"})
public String saveSeedstarter(
final SeedStarter seedStarter, final BindingResult bindingResult, final ModelMap model) {
if ([Link]()) {
return "seedstartermng";
}
[Link](seedStarter);
[Link]();
return "redirect:/seedstartermng";
}

4.5 Con gurando um serviço de conversão

Para permitir a formatação fácil Date e também dos Variety objetos em nossa camada de visualização, con guramos nosso
aplicativo para que um ConversionService objeto Spring fosse criado e inicializado (conforme
WebMvcConfigurerAdapter estendemos) com alguns objetos do formatador que precisaremos. Veja novamente:

@Override
public void addFormatters(final FormatterRegistry registry) {
[Link](registry);
[Link](varietyFormatter());
[Link] 12/34
01/08/2020 Tutorial: Thymeleaf + Spring
[Link](dateFormatter());
}

@Bean
public VarietyFormatter varietyFormatter() {
return new VarietyFormatter();
}

@Bean
public DateFormatter dateFormatter() {
return new DateFormatter();
}

Formatadores Spring são implementações da [Link] interface. Para obter mais informações
sobre como a infraestrutura de conversão do Spring funciona, consulte os documentos em [Link] .

Vamos dar uma olhada em DateFormatter , que formata as datas de acordo com uma string de formato presente na
[Link] chave de mensagem do nosso [Link] :

public class DateFormatter implements Formatter<Date> {

@Autowired
private MessageSource messageSource;

public DateFormatter() {
super();
}

public Date parse(final String text, final Locale locale) throws ParseException {
final SimpleDateFormat dateFormat = createDateFormat(locale);
return [Link](text);
}

public String print(final Date object, final Locale locale) {


final SimpleDateFormat dateFormat = createDateFormat(locale);
return [Link](object);
}

private SimpleDateFormat createDateFormat(final Locale locale) {


final String format = [Link]("[Link]", null, locale);
final SimpleDateFormat dateFormat = new SimpleDateFormat(format);
[Link](false);
return dateFormat;
}

O VarietyFormatter converte automaticamente entre nossas Variety entidades e a maneira como queremos usá-los em
nossos formulários (basicamente, pelos id valores de campo):

public class VarietyFormatter implements Formatter<Variety> {

@Autowired
private VarietyService varietyService;

public VarietyFormatter() {
super();
}

public Variety parse(final String text, final Locale locale) throws ParseException {
final Integer varietyId = [Link](text);
return [Link](varietyId);
}

[Link] 13/34
01/08/2020 Tutorial: Thymeleaf + Spring

public String print(final Variety object, final Locale locale) {


return (object != null ? [Link]().toString() : "");
}

Aprenderemos mais sobre como esses formatadores afetam a maneira como nossos dados são exibidos posteriormente.

[Link] 14/34
01/08/2020 Tutorial: Thymeleaf + Spring

5 Listando dados iniciais de sementes


A primeira coisa que nossa /WEB-INF/templates/[Link] página mostrará é uma lista com os iniciantes de
sementes atualmente armazenados. Para isso, precisaremos de algumas mensagens externalizadas e também alguma
avaliação de expressão nos atributos do modelo. Como isso:

<div class="seedstarterlist" th:unless="${#[Link](allSeedStarters)}">

<h2 th:text="#{[Link]}">List of Seed Starters</h2>

<table>
<thead>
<tr>
<th th:text="#{[Link]}">Date Planted</th>
<th th:text="#{[Link]}">Covered</th>
<th th:text="#{[Link]}">Type</th>
<th th:text="#{[Link]}">Features</th>
<th th:text="#{[Link]}">Rows</th>
</tr>
</thead>
<tbody>
<tr th:each="sb : ${allSeedStarters}">
<td th:text="${{[Link]}}">13/01/2011</td>
<td th:text="#{|bool.${[Link]}|}">yes</td>
<td th:text="#{|[Link].${[Link]}|}">Wireframe</td>
<td th:text="${#[Link](
#[Link](
#[Link]([Link],'[Link].')),
', ')}">Electric Heating, Turf</td>
<td>
<table>
<tbody>
<tr th:each="row,rowStat : ${[Link]}">
<td th:text="${[Link]}">1</td>
<td th:text="${[Link]}">Thymus Thymi</td>
<td th:text="${[Link]}">12</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>

Muito para ver aqui. Vamos dar uma olhada em cada fragmento separadamente.

Antes de tudo, esta seção só será mostrada se houver alguma partida inicial. Conseguimos isso com um th: a menos que
atributo e a #[Link](...) função.

<div class="seedstarterlist" th:unless="${#[Link](allSeedStarters)}">

Observe que todos os objetos utilitários como #lists estão disponíveis nas expressões Spring EL da mesma maneira que
estavam nas expressões OGNL no Dialeto padrão.

A próxima coisa a ver são muitos textos internacionalizados (externalizados), como:

<h2 th:text="#{[Link]}">List of Seed Starters</h2>

<table>
<thead>

[Link] 15/34
01/08/2020 Tutorial: Thymeleaf + Spring
<tr>
<th th:text="#{[Link]}">Date Planted</th>
<th th:text="#{[Link]}">Covered</th>
<th th:text="#{[Link]}">Type</th>
<th th:text="#{[Link]}">Features</th>
<th th:text="#{[Link]}">Rows</th>
...

Por ser um aplicativo Spring MVC, já de nimos um MessageSource bean em nossa con guração do Spring (os
MessageSource objetos são a maneira padrão de gerenciar textos externalizados no Spring MVC):

@Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
[Link]("Messages");
return messageSource;
}

… E essa basename propriedade indica que teremos arquivos como Messages_es.properties ou Messages_en.properties em
nosso caminho de classe. Vamos dar uma olhada na versão em espanhol:

[Link]=Lista de semilleros

[Link]=dd/MM/yyyy
[Link]=sí
[Link]=no

[Link]=Fecha de plantación
[Link]=Cubierto
[Link]=Tipo
[Link]=Características
[Link]=Filas

[Link]=Madera
[Link]=Plástico

[Link].SEEDSTARTER_SPECIFIC_SUBSTRATE=Sustrato específico para semilleros


[Link]=Fertilizante
[Link].PH_CORRECTOR=Corrector de PH

Na primeira coluna da lista de tabelas, mostraremos a data em que o iniciador de sementes foi preparado. Mas nós o
mostraremos formatado da maneira que de nimos em nosso DateFormatter . Para isso, usaremos a sintaxe de colchete
duplo ( ${{...}} ), que aplicará automaticamente o Serviço de Conversão Spring, incluindo o DateFormatter que registramos
na con guração.

<td th:text="${{[Link]}}">13/01/2011</td>

A seguir, mostramos se o contêiner do iniciador de sementes está coberto ou não, transformando o valor da propriedade
booleana do bean coberto em um internacionalizado "yes" ou "no" com uma expressão de substituição literal:

<td th:text="#{|bool.${[Link]}|}">yes</td>

Agora temos que mostrar o tipo de contêiner de iniciador de sementes. Type é uma enumeração java com dois valores (
WOOD e PLASTIC ), e é por isso que de nimos duas propriedades em nosso Messages arquivo chamado
[Link] and [Link] .

Mas, para obter os nomes internacionalizados dos tipos, precisaremos adicionar o [Link]. pre xo ao valor da
enumeração por meio de uma expressão, cujo resultado usaremos como chave de mensagem:

<td th:text="#{|[Link].${[Link]}|}">Wireframe</td>

[Link] 16/34
01/08/2020 Tutorial: Thymeleaf + Spring

A parte mais difícil desta listagem é a coluna de recursos . Nele, queremos exibir todos os recursos de nosso contêiner - que
vêm na forma de uma matriz de Feature enumerações -, separados por vírgulas. Como "Aquecimento elétrico, relva" .

Observe que isso é particularmente difícil porque esses valores de enum também precisam ser externalizados, como zemos
com Types. O uxo é então:

1. Anexe o pre xo correspondente a todos os elementos da features matriz.


2. Obtenha as mensagens externalizadas correspondentes a todas as chaves da etapa 1.
3. Junte todas as mensagens obtidas na etapa 2, usando uma vírgula como delimitador.

Para conseguir isso, criamos o seguinte código:

<td th:text="${#[Link](
#[Link](
#[Link]([Link],'[Link].')),
', ')}">Electric Heating, Turf</td>

A última coluna da nossa listagem será bastante simples. Mesmo se houver uma tabela aninhada para mostrar o conteúdo de
cada linha no contêiner:

<td>
<table>
<tbody>
<tr th:each="row,rowStat : ${[Link]}">
<td th:text="${[Link]}">1</td>
<td th:text="${[Link]}">Thymus Thymi</td>
<td th:text="${[Link]}">12</td>
</tr>
</tbody>
</table>
</td>

[Link] 17/34
01/08/2020 Tutorial: Thymeleaf + Spring

6 Criando um formulário

6.1 Manipulando o objeto de comando

Objeto de comando é o nome que o Spring MVC atribui aos beans de backup de formulário, ou seja, aos objetos que modelam
os campos de um formulário e fornecem métodos getter e setter que serão usados pela estrutura para estabelecer e obter
os valores inseridos pelo usuário no navegador lado.

O Thymeleaf requer que você especi que o objeto de comando usando um th:object atributo em sua <form> tag:

<form action="#" th:action="@{/seedstartermng}" th:object="${seedStarter}" method="post">


...
</form>

Isso é consistente com outros usos, th:object, mas, na verdade, esse cenário especí co adiciona algumas limitações para
integrar-se corretamente à infraestrutura do Spring MVC:

Os valores para th:object atributos em tags de formulário devem ser expressões variáveis ( ${...} ) especi cando
apenas o nome de um atributo de modelo, sem navegação de propriedade. Isso signi ca que uma expressão como
${seedStarter} é válida, mas ${[Link]} não seria.
Uma vez dentro da <form> tag, nenhum outro th:object atributo pode ser especi cado. Isso é consistente com o fato de
que os formulários HTML não podem ser aninhados.

6.2 Entradas

Vamos ver agora como adicionar uma entrada ao nosso formulário:

<input type="text" th:field="*{datePlanted}" />

Como você pode ver, estamos introduzindo um novo atributo aqui: th:field. Esse é um recurso muito importante para a
integração do Spring MVC porque faz todo o trabalho pesado de vincular sua entrada a uma propriedade no bean de backup
de formulário. Você pode vê-lo como um equivalente do atributo path em um tag da biblioteca de tags JSP do Spring MVC.

O th:field atributo se comporta de maneira diferente, dependendo de estar anexado a uma tag <input> , <select> ou
<textarea> (e também dependendo do tipo especí co de <input> tag). Nesse caso ( input[type=text] ), a linha de código
acima é semelhante a:

<input type="text" id="datePlanted" name="datePlanted" th:value="*{datePlanted}" />

… Mas, na verdade, é um pouco mais do que isso, porque th:field também aplicará o Serviço de conversão de primavera
registrado, incluindo o DateFormatter que vimos anteriormente (mesmo que a expressão de campo não esteja entre
colchetes duplos). Graças a isso, a data será mostrada corretamente formatada.

Os valores para th:field atributos devem ser expressões de seleção ( *{...} ), o que faz sentido, pois eles serão avaliados
no bean de backup de formulário e não nas variáveis de contexto (ou atributos de modelo no jargão do Spring MVC).

Ao contrário do que está dentro th:object , essas expressões podem incluir navegação de propriedade (de fato, qualquer
expressão permitida para o atributo path de uma <form:input> tag JSP será permitida aqui).

Note-se que th:field também compreende os novos tipos de <input> elemento introduzido pelo HTML5 como <input
type="datetime" ... /> , <input type="color" ... /> , etc., acrescentando efetivamente suporte completo HTML5 para
Spring MVC.

[Link] 18/34
01/08/2020 Tutorial: Thymeleaf + Spring

6.3 Campos da caixa de seleção

th:field também nos permite de nir entradas da caixa de seleção. Vamos ver um exemplo da nossa página HTML:

<div>
<label th:for="${#[Link]('covered')}" th:text="#{[Link]}">Covered</label>
<input type="checkbox" th:field="*{covered}" />
</div>

Observe que há algumas coisas boas aqui além da própria caixa de seleção, como um rótulo externalizado e também o uso da
#[Link]('covered') função para obter o valor que será aplicado ao atributo id da entrada da caixa de seleção.

Por que precisamos dessa geração dinâmica de um atributo id para esse campo? Como as caixas de seleção são
potencialmente com vários valores e, portanto, seus valores de ID sempre terão o su xo de um número de sequência (usando
internamente a #[Link](...) função) para garantir que cada uma das entradas da caixa de seleção da mesma propriedade
tenha um valor de ID diferente.

Podemos ver isso mais facilmente se observarmos um campo de caixa de seleção com vários valores:

<ul>
<li th:each="feat : ${allFeatures}">
<input type="checkbox" th:field="*{features}" th:value="${feat}" />
<label th:for="${#[Link]('features')}"
th:text="#{${'[Link].' + feat}}">Heating</label>
</li>
</ul>

Observe que th:value desta vez adicionamos um atributo, porque o campo de recursos não é um booleano como o coberto
foi, mas sim uma matriz de valores.

Vamos ver a saída HTML gerada por este código:

<ul>
<li>
<input id="features1" name="features" type="checkbox" value="SEEDSTARTER_SPECIFIC_SUBSTRATE" />
<input name="_features" type="hidden" value="on" />
<label for="features1">Seed starter-specific substrate</label>
</li>
<li>
<input id="features2" name="features" type="checkbox" value="FERTILIZER" />
<input name="_features" type="hidden" value="on" />
<label for="features2">Fertilizer used</label>
</li>
<li>
<input id="features3" name="features" type="checkbox" value="PH_CORRECTOR" />
<input name="_features" type="hidden" value="on" />
<label for="features3">PH Corrector used</label>
</li>
</ul>

Podemos ver aqui como um su xo de sequência é adicionado ao atributo de id de cada entrada e como a
#[Link](...) função nos permite recuperar o último valor de sequência gerado para um ID de entrada especí co.

Não se preocupe com essas entradas ocultas com name="_features" : elas são automaticamente adicionadas para
evitar problemas com os navegadores que não enviam valores de caixa de seleção desmarcados ao servidor após o
envio do formulário.

Observe também que, se nossa propriedade features contivesse alguns valores selecionados em nosso bean de backup de
formulário, th:field isso teria sido resolvido e adicionado um checked="checked" atributo às tags de entrada

[Link] 19/34
01/08/2020 Tutorial: Thymeleaf + Spring

correspondentes.

6.4 Campos dos botões de opção

Os campos dos botões de opção são especi cados de maneira semelhante às caixas de seleção não booleanas (com vários
valores) - exceto que eles não têm vários valores, é claro:

<ul>
<li th:each="ty : ${allTypes}">
<input type="radio" th:field="*{type}" th:value="${ty}" />
<label th:for="${#[Link]('type')}" th:text="#{${'[Link].' + ty}}">Wireframe</label>
</li>
</ul>

6.5 Seletores suspensos / lista

Os campos de seleção têm duas partes: a <select> marca e suas <option> marcas aninhadas . Ao criar esse tipo de campo,
apenas a <select> tag precisa incluir um th:field atributo, mas os th:value atributos nas <option> tags aninhadas serão
muito importantes porque fornecerão os meios de saber qual é a opção atualmente selecionada (de maneira semelhante à
não-booleana caixas de seleção e botões de opção).

Vamos recriar o campo de tipo como uma seleção suspensa:

<select th:field="*{type}">
<option th:each="type : ${allTypes}"
th:value="${type}"
th:text="#{${'[Link].' + type}}">Wireframe</option>
</select>

Neste ponto, entender esse pedaço de código é bastante fácil. Observe como a precedência de atributo nos permite de nir o
th:each atributo na <option> própria tag.

6.6 Campos dinâmicos

Graças aos recursos avançados de ligação de campo de formulário no Spring MVC, podemos usar expressões complexas do
Spring EL para vincular campos de formulário dinâmicos ao nosso bean de backup de formulário. Isso nos permitirá criar
novos objetos Row em nosso SeedStarter bean e adicionar os campos dessas linhas ao nosso formulário, mediante
solicitação do usuário.

Para fazer isso, precisaremos de alguns novos métodos mapeados em nosso controlador, que adicionarão ou removerão uma
linha da nossa, SeedStarter dependendo da existência de parâmetros de solicitação especí cos:

@RequestMapping(value="/seedstartermng", params={"addRow"})
public String addRow(final SeedStarter seedStarter, final BindingResult bindingResult) {
[Link]().add(new Row());
return "seedstartermng";
}

@RequestMapping(value="/seedstartermng", params={"removeRow"})
public String removeRow(
final SeedStarter seedStarter, final BindingResult bindingResult,
final HttpServletRequest req) {
final Integer rowId = [Link]([Link]("removeRow"));
[Link]().remove([Link]());
return "seedstartermng";
}

[Link] 20/34
01/08/2020 Tutorial: Thymeleaf + Spring

E agora podemos adicionar uma tabela dinâmica ao nosso formulário:

<table>
<thead>
<tr>
<th th:text="#{[Link]}">Row</th>
<th th:text="#{[Link]}">Variety</th>
<th th:text="#{[Link]}">Seeds per cell</th>
<th>
<button type="submit" name="addRow" th:text="#{[Link]}">Add row</button>
</th>
</tr>
</thead>
<tbody>
<tr th:each="row,rowStat : *{rows}">
<td th:text="${[Link]}">1</td>
<td>
<select th:field="*{rows[__${[Link]}__].variety}">
<option th:each="var : ${allVarieties}"
th:value="${[Link]}"
th:text="${[Link]}">Thymus Thymi</option>
</select>
</td>
<td>
<input type="text" th:field="*{rows[__${[Link]}__].seedsPerCell}" />
</td>
<td>
<button type="submit" name="removeRow"
th:value="${[Link]}" th:text="#{[Link]}">Remove row</button>
</td>
</tr>
</tbody>
</table>

Muitas coisas para ver aqui, mas não muito que não devemos entender até agora ... exceto por uma strange coisa:

<select th:field="*{rows[__${[Link]}__].variety}">

...

</select>

Se você se lembra do tutorial “Usando o Thymeleaf” , essa __${...}__ sintaxe é uma expressão de pré-processamento, que é
uma expressão interna que é avaliada antes de realmente avaliar toda a expressão. Mas por que essa maneira de especi car o
índice de linha? Não seria su ciente com:

<select th:field="*{rows[[Link]].variety}">

...

</select>

... bem, na verdade não. O problema é que a Primavera EL não avalia variáveis dentro de chaves de índice de matriz, de modo
ao executar a expressão acima obteríamos um erro nos dizendo que rows[[Link]] (em vez de rows[0] , rows[1] , etc)
não é uma posição válida na coleção de linhas. É por isso que o pré-processamento é necessário aqui.

Vamos dar uma olhada em um fragmento do HTML resultante depois de pressionar "Adicionar linha" algumas vezes:

<tbody>
<tr>
<td>1</td>
<td>

[Link] 21/34
01/08/2020 Tutorial: Thymeleaf + Spring
<select id="[Link]" name="rows[0].variety">
<option selected="selected" value="1">Thymus vulgaris</option>
<option value="2">Thymus x citriodorus</option>
<option value="3">Thymus herba-barona</option>
<option value="4">Thymus pseudolaginosus</option>
<option value="5">Thymus serpyllum</option>
</select>
</td>
<td>
<input id="[Link]" name="rows[0].seedsPerCell" type="text" value="" />
</td>
<td>
<button name="removeRow" type="submit" value="0">Remove row</button>
</td>
</tr>
<tr>
<td>2</td>
<td>
<select id="[Link]" name="rows[1].variety">
<option selected="selected" value="1">Thymus vulgaris</option>
<option value="2">Thymus x citriodorus</option>
<option value="3">Thymus herba-barona</option>
<option value="4">Thymus pseudolaginosus</option>
<option value="5">Thymus serpyllum</option>
</select>
</td>
<td>
<input id="[Link]" name="rows[1].seedsPerCell" type="text" value="" />
</td>
<td>
<button name="removeRow" type="submit" value="1">Remove row</button>
</td>
</tr>
</tbody>

[Link] 22/34
01/08/2020 Tutorial: Thymeleaf + Spring

7 Validação e mensagens de erro


A maioria dos nossos formulários precisará mostrar mensagens de validação para informar o usuário sobre os erros que ele /
ela cometeu.

O Thymeleaf oferece algumas ferramentas para isso: algumas funções no #fields objeto, the th:errors e os
th:errorclass atributos.

7.1 Erros de campo

Vamos ver como podemos de nir uma classe CSS especí ca para um campo, se houver um erro:

<input type="text" th:field="*{datePlanted}"


th:class="${#[Link]('datePlanted')}? fieldError" />

Como você pode ver, a #[Link](...) função recebe a expressão do campo como um parâmetro ( datePlanted ) e
retorna um booleano informando se existem erros de validação para esse campo.

Também podemos obter todos os erros desse campo e iterá-los:

<ul>
<li th:each="err : ${#[Link]('datePlanted')}" th:text="${err}" />
</ul>

Em vez de iterar, também poderíamos usar th:errors um atributo especializado que cria uma lista com todos os erros do
seletor especi cado, separados por <br /> :

<input type="text" th:field="*{datePlanted}" />


<p th:if="${#[Link]('datePlanted')}" th:errors="*{datePlanted}">Incorrect date</p>

Simpli cando o estilo CSS baseado em erro: th:errorclass

O exemplo vimos acima, de nindo uma classe CSS para uma entrada de formulário se esse campo tem erros , é tão comum que
Thymeleaf oferece um atributo especí co para fazer exacly que: th:errorclass .

Aplicada a um tag campo de formulário (input, selecionar, textarea ...), ele irá ler o nome do campo para ser examinado a
partir de qualquer existente name ou th:field atributos na mesma tag, e em seguida, acrescentar a classe CSS especi cado
para a tag se tal campo tem quaisquer erros associados:

<input type="text" th:field="*{datePlanted}" class="small" th:errorclass="fieldError" />

Se datePlanted houver erros, isso será renderizado como:

<input type="text" id="datePlanted" name="datePlanted" value="2013-01-01" class="small fieldError" />

7.2 Todos os erros

E se quisermos mostrar todos os erros no formulário? Nós apenas precisamos de consultar os #[Link](...) e
#[Link](...) métodos com os '*' ou 'all' constantes (que são equivalentes):

[Link] 23/34
01/08/2020 Tutorial: Thymeleaf + Spring

<ul th:if="${#[Link]('*')}">
<li th:each="err : ${#[Link]('*')}" th:text="${err}">Input is incorrect</li>
</ul>

Como nos exemplos acima, podemos obter todos os erros e iterá-los…

<ul>
<li th:each="err : ${#[Link]('*')}" th:text="${err}" />
</ul>

… Bem como criar uma <br /> lista separada:

<p th:if="${#[Link]('all')}" th:errors="*{all}">Incorrect date</p>

Finalmente, note que #[Link]('*') é equivalente a #[Link]() e #[Link]('*') é


equivalente a #[Link]() . Use a sintaxe que você preferir:

<div th:if="${#[Link]()}">
<p th:each="err : ${#[Link]()}" th:text="${err}">...</p>
</div>

7.3 Erros globais

Há um terceiro tipo de erro no formulário Spring: erros globais . Esses são erros que não estão associados a nenhum campo
especí co no formulário, mas ainda existem.

O Thymeleaf oferece a global constante para acessar estes erros:

<ul th:if="${#[Link]('global')}">
<li th:each="err : ${#[Link]('global')}" th:text="${err}">Input is incorrect</li>
</ul>

<p th:if="${#[Link]('global')}" th:errors="*{global}">Incorrect date</p>

… Bem como métodos equivalentes #[Link]() e #[Link]() convenientes:

<div th:if="${#[Link]()}">
<p th:each="err : ${#[Link]()}" th:text="${err}">...</p>
</div>

7.4 Exibindo erros fora dos formulários

Os erros de validação de formulário também podem ser exibidos fora dos formulários usando expressões de variável (
${...} ) em vez de selection ( *{...} ) e pre xando o nome do bean de backup de formulário:

<div th:errors="${myForm}">...</div>
<div th:errors="${[Link]}">...</div>
<div th:errors="${myForm.*}">...</div>

<div th:if="${#[Link]('${myForm}')}">...</div>
<div th:if="${#[Link]('${[Link]}')}">...</div>
<div th:if="${#[Link]('${myForm.*}')}">...</div>

[Link] 24/34
01/08/2020 Tutorial: Thymeleaf + Spring
<form th:object="${myForm}">
...
</form>

7.5 Objetos de erro avançados

O Thymeleaf oferece a possibilidade de obter informações de erro de formulário na forma de beans (em vez de meras strings
), com os atributos fieldName (String), message (String) e global (booleano).

Esses erros podem ser obtidos por meio do #[Link]() método utilitário:

<ul>
<li th:each="e : ${#[Link]()}" th:class="${[Link]}? globalerr : fielderr">
<span th:text="${[Link]}? '*' : ${[Link]}">The field name</span> |
<span th:text="${[Link]}">The error message</span>
</li>
</ul>

[Link] 25/34
01/08/2020 Tutorial: Thymeleaf + Spring

8 Ainda é um protótipo!
Nossa aplicação está pronta agora. Mas vamos dar uma segunda olhada na .html página que criamos ...

Uma das conseqüências mais agradáveis de trabalhar com o Thymeleaf é que, depois de toda essa funcionalidade que
adicionamos ao nosso HTML, ainda podemos usá-lo como um protótipo (dizemos que é um Modelo Natural ). Vamos abrir
[Link] diretamente em nosso navegador sem executar nosso aplicativo:

Modelo natural STSM

Aí está! Não é um aplicativo funcional, não são dados reais ... mas é um protótipo perfeitamente válido, composto de código
HTML perfeitamente exibível.

[Link] 26/34
01/08/2020 Tutorial: Thymeleaf + Spring

9 O serviço de conversão

9.1 Con guração

Como explicado anteriormente, o Thymeleaf pode usar um Serviço de Conversão registrado no Contexto do Aplicativo. Nossa
classe de con guração de aplicativos, estendendo o próprio WebMvcConfigurerAdapter auxiliar do Spring , registrará
automaticamente esse serviço de conversão, que podemos con gurar adicionando os formatadores de que precisamos.
Vamos ver novamente como é:

@Override
public void addFormatters(final FormatterRegistry registry) {
[Link](registry);
[Link](varietyFormatter());
[Link](dateFormatter());
}

@Bean
public VarietyFormatter varietyFormatter() {
return new VarietyFormatter();
}

@Bean
public DateFormatter dateFormatter() {
return new DateFormatter();
}

9.1 Sintaxe de chaves duplas

O Serviço de Conversão pode ser facilmente aplicado para converter / formatar qualquer objeto em String. Isso é feito por
meio da sintaxe da expressão entre chaves:

Para expressões variáveis: ${{...}}


Para expressões de seleção: *{{...}}

Assim, por exemplo, dado um conversor de número inteiro em cadeia que adiciona vírgulas como separador de milhares, isso:

<p th:text="${val}">...</p>
<p th:text="${{val}}">...</p>

… Deve resultar em:

<p>1234567890</p>
<p>1,234,567,890</p>

9.2 Uso em formulários

Vimos anteriormente que cada th:field atributo sempre aplicará o serviço de conversão, portanto, este:

<input type="text" th:field="*{datePlanted}" />

... é realmente equivalente a:

[Link] 27/34
01/08/2020 Tutorial: Thymeleaf + Spring

<input type="text" th:field="*{{datePlanted}}" />

Observe que, por exigência do Spring, este é o único cenário em que o Serviço de Conversão é aplicado em expressões
usando a sintaxe de chave única.

9.3 #conversionsobjeto utilitário

O #conversions objeto utilitário de expressão permite a execução manual do Serviço de Conversão sempre que necessário:

<p th:text="${'Val: ' + #[Link](val,'String')}">...</p>

Sintaxe para este objeto utilitário:

#[Link](Object,Class) : converte o objeto na classe especi cada.


#[Link](Object,String) : igual ao acima, mas especi cando a classe de destino como uma String (observe
que o [Link]. pacote pode ser omitido).

[Link] 28/34
01/08/2020 Tutorial: Thymeleaf + Spring

10 fragmentos de modelo de renderização


O Thymeleaf oferece a possibilidade de renderizar apenas parte de um modelo como resultado de sua execução: um
fragmento .

Essa pode ser uma ferramenta de componente útil. Por exemplo, ele pode ser usado em controladores executados em
chamadas AJAX, que podem retornar fragmentos de marcação de uma página que já está carregada no navegador (para
atualizar botões de seleção, ativação / desativação ...).

A renderização fragmentária pode ser obtida usando as especi cações de fragmento do Thymeleaf : objetos implementando a
[Link] interface.

A mais comum dessas implementações é [Link] , que permite


especi car um fragmento usando um Seletor DOM exatamente como os usados em th:include ou th:replace .

10.1 Especi cando fragmentos nos beans de exibição

View beans são beans da [Link] classe declarada no contexto do aplicativo (


@Bean declarações se você estiver usando a con guração Java). Eles permitem a especi cação de fragmentos como este:

@Bean(name="content-part")
@Scope("prototype")
public ThymeleafView someViewBean() {
ThymeleafView view = new ThymeleafView("index"); // templateName = 'index'
[Link]("content");
return view;
}

Dada a de nição do bean acima, se nosso controlador retornar content-part (o nome do bean acima)…

@RequestMapping("/showContentPart")
public String showContentPart() {
...
return "content-part";
}

… Thymeleaf retornará apenas o content fragmento do index modelo - que local provavelmente será algo assim /WEB-
INF/templates/[Link] , quando o pre xo e o su xo forem aplicados. Portanto, o resultado será completamente
equivalente a especi car index :: content :

<!DOCTYPE html>
<html>
...
<body>
...
<div th:fragment="content">
Only this div will be rendered!
</div>
...
</body>
</html>

Observe também que, graças ao poder dos seletores de marcação Thymeleaf, podemos selecionar um fragmento em um
modelo sem precisar de nenhum th:fragment atributo. Vamos usar o id atributo, por exemplo:

[Link] 29/34
01/08/2020 Tutorial: Thymeleaf + Spring

@Bean(name="content-part")
@Scope("prototype")
public ThymeleafView someViewBean() {
ThymeleafView view = new ThymeleafView("index"); // templateName = 'index'
[Link]("#content");
return view;
}

… Que selecionará perfeitamente:

<!DOCTYPE html>
<html>
...
<body>
...
<div id="content">
Only this div will be rendered!
</div>
...
</body>
</html>

10.2 Especi cando fragmentos nos valores de retorno do controlador

Em vez de declarar os beans de exibição , os fragmentos podem ser especi cados nos próprios controladores usando a sintaxe
das expressões de fragmento . Assim como em th:insert ou th:replace atributos:

@RequestMapping("/showContentPart")
public String showContentPart() {
...
return "index :: content";
}

Obviamente, novamente todo o poder dos Seletores DOM está disponível, para que possamos selecionar nosso fragmento
com base nos atributos HTML padrão, como id="content" :

@RequestMapping("/showContentPart")
public String showContentPart() {
...
return "index :: #content";
}

E também podemos usar parâmetros, como:

@RequestMapping("/showContentPart")
public String showContentPart() {
...
return "index :: #content ('myvalue')";
}

[Link] 30/34
01/08/2020 Tutorial: Thymeleaf + Spring

11 Recursos avançados de integração

11.1 Integração com RequestDataValueProcessor

O Thymeleaf se integra perfeitamente à RequestDataValueProcessor interface do Spring . Essa interface permite a


interceptação de URLs de link, URLs de formulário e valores de campo de formulário antes de serem gravados no resultado
da marcação, além de adicionar de forma transparente campos de formulário ocultos que ativam recursos de segurança
como, por exemplo, proteção contra CSRF (falsi cação de solicitação entre sites).

Uma implementação de RequestDataValueProcessor pode ser facilmente con gurada no contexto do aplicativo. Ele precisa
implementar a [Link] interface e ter
requestDataValueProcessor como nome de bean:

@Bean
public RequestDataValueProcessor requestDataValueProcessor() {
return new MyRequestDataValueProcessor();
}

… E o Thymeleaf o usará desta maneira:

th:href e th:src ligue [Link](...) antes de renderizar o URL.

th:action chama [Link](...) antes de renderizar o action atributo do formulário


e, além disso, detecta quando esse atributo está sendo aplicado a uma <form> tag - que deve ser o único local - e, nesse
caso, chama [Link](...) e adiciona os campos ocultos retornados
imediatamente antes da </form> tag de fechamento .

th:value solicita [Link](...) a renderização do valor a que se refere, a


menos que haja um th:field presente na mesma tag (nesse caso, th:field será necessário).

th:field solicita [Link](...) a renderização do valor do campo ao qual se


aplica (ou o corpo da tag, se for um <textarea> ).

Observe que existem muito poucos cenários nos quais você precisaria implementar explicitamente
RequestDataValueProcessor em seu aplicativo. Na maioria dos casos, isso será usado automaticamente pelas
bibliotecas de segurança que você usa de forma transparente, como por exemplo, o suporte a CSRF da Spring Security.

11.1 Criando URIs para controladores

Desde a versão 4.1, o Spring permite a possibilidade de criar links para controladores anotados diretamente das visualizações,
sem a necessidade de conhecer os URIs para os quais esses controladores são mapeados.

No Thymeleaf, isso pode ser conseguido por meio do #[Link](...) método de objeto de expressão, que permite a
especi cação de métodos de controlador pelas letras maiúsculas da classe de controlador em que eles estão, seguidos pelo
nome do próprio método. Isso é equivalente à spring:mvcUrl(...) função customizada do JSP .

Por exemplo, para:

public class ExampleController {

@RequestMapping("/data")
public String getData(Model model) { ... return "template" }

@RequestMapping("/data")
[Link] 31/34
01/08/2020 Tutorial: Thymeleaf + Spring
public String getDataParam(@RequestParam String type) { ... return "template" }

O código a seguir criará um link para ele:

<a th:href="${(#[Link]('EC#getData')).build()}">Get Data Param</a>


<a th:href="${(#[Link]('EC#getDataParam').arg(0,'internal')).build()}">Get Data Param</a>

Você pode ler mais sobre esse mecanismo em [Link]


reference/html/[Link]#mvc-links-to-controllers- de visualizações

[Link] 32/34
01/08/2020 Tutorial: Thymeleaf + Spring

12 Integração do Spring WebFlow

12.1 Con guração básica

Os pacotes de integração Thymeleaf + Spring incluem integração com o Spring WebFlow (2.3+).

O WebFlow inclui alguns recursos do AJAX para renderizar fragmentos da página exibida quando eventos especí cos (
transições ) são acionados e, para permitir que o Thymeleaf atenda a essas solicitações do AJAX, teremos que usar uma
ViewResolver implementação diferente , con gurada da seguinte forma:

<bean id="thymeleafViewResolver" class="[Link]">


<property name="viewClass" value="[Link]" />
<property name="templateEngine" ref="templateEngine" />
</bean>

… E isso ViewResolver pode ser con gurado no seu WebFlow ViewFactoryCreator como:

<bean id="mvcViewFactoryCreator"
class="[Link]">
<property name="viewResolvers" ref="thymeleafViewResolver"/>
</bean>

A partir daqui, você pode especi car modelos Thymeleaf nos seus estados de exibição:

<view-state id="detail" view="bookingDetail">


...
</view-state>

No exemplo acima, bookingDetail é um modelo Thymeleaf especi cado da maneira usual, compreensível por qualquer um
dos Resolvedores de modelos con gurados no TemplateEngine .

12.2 Fragmentos AJAX no Spring WebFlow

Observe que o que é explicado aqui é apenas a maneira de criar fragmentos AJAX para serem usados com o Spring
WebFlow. Se você não estiver usando o WebFlow, criar um controlador Spring MVC que responda a uma solicitação
AJAX e retorne um pedaço de HTML é tão simples quanto criar qualquer outro controlador de retorno de modelo, com
a única exceção de que você provavelmente retornaria um fragmento como "main :: admin" de seu método de
controle.

O WebFlow permite que a especi cação de fragmentos seja renderizada via AJAX com <render> tags, assim:

<view-state id="detail" view="bookingDetail">


<transition on="updateData">
<render fragments="hoteldata"/>
</transition>
</view-state>

Esses fragmentos ( hoteldata nesse caso) podem ser uma lista separada por vírgula de fragmentos especi cada na marcação
com th:fragment :

[Link] 33/34
01/08/2020 Tutorial: Thymeleaf + Spring

<div id="data" th:fragment="hoteldata">


This is a content to be changed
</div>

Lembre-se sempre de que os fragmentos especi cados devem ter um idatributo, para que as bibliotecas Spring JavaScript em
execução no navegador possam substituir a marcação.

<render> As tags também podem ser especi cadas usando os seletores DOM:

<view-state id="detail" view="bookingDetail">


<transition on="updateData">
<render fragments="[//div[@id='data']]"/>
</transition>
</view-state>

… E isso signi ca que não th:fragment é necessário:

<div id="data">
This is a content to be changed
</div>

Quanto ao código que aciona a updateData transição, ele se parece com:

<script type="text/javascript" th:src="@{/resources/dojo/[Link]}"></script>


<script type="text/javascript" th:src="@{/resources/spring/[Link]}"></script>
<script type="text/javascript" th:src="@{/resources/spring/[Link]}"></script>

...

<form id="triggerform" method="post" action="">


<input type="submit" id="doUpdate" name="_eventId_updateData" value="Update now!" />
</form>

<script type="text/javascript">
[Link](
new [Link]({formId:'triggerform',elementId:'doUpdate',event:'onclick'}));
</script>

[Link] 34/34

Você também pode gostar