The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
Edit this Page

Template de uso do Qute

O Qute é um mecanismo de criação de modelos desenvolvido especificamente para o Quarkus. O uso de reflections é minimizado para reduzir o tamanho das imagens nativas. A API combina o estilo de codificação imperativa e o estilo reativo sem bloqueio. No modo de desenvolvimento, todos os arquivos localizados em src/main/resources/templates são monitorados quanto a alterações, e as modificações tornam-se visíveis imediatamente. Além disso, nosso objetivo é detectar a maioria dos problemas de modelo no momento da compilação. Neste guia, você aprenderá a renderizar facilmente os modelos em sua aplicação.

Solução

Recomendamos que siga as instruções nas seções seguintes e crie a aplicação passo a passo. No entanto, você pode ir diretamente para o exemplo completo.

Clone o repositório Git: git clone https://github.com/quarkusio/quarkus-quickstarts.git, ou baixe um arquivo.

A solução está localizada no diretório qute-quickstart.

Disponibilizando os templates do Qute via HTTP

Se você quiser disponibilizar seus templates via HTTP:

  1. A extensão Qute Web permite que você veja diretamente os templates HTTP localizados em src/main/resources/templates/pub/ . Nesse caso, não é necessário nenhum código Java para "conectar" o template; por exemplo, o template src/main/resources/templates/pub/foo.html será exibido a partir dos caminhos /foo e /foo.html por padrão.

  2. Para um controle mais preciso, é possível combiná-lo com o Quarkus REST para controlar como o template será exibido. Todos os arquivos localizados no diretório src/main/resources/templates e seus subdiretórios são registrados como templates e podem ser injetados em um recurso REST.

pom.xml
<dependency>
    <groupId>io.quarkiverse.qute.web</groupId>
    <artifactId>quarkus-qute-web</artifactId>
</dependency>
build.gradle
implementation("io.quarkiverse.qute.web:quarkus-qute-web")
The Qute Web extension, while hosted in the Quarkiverse, is part of the Quarkus Platform and its version is defined in the Quarkus Platform BOM.

Exibindo o Hello World com o Qute

Let’s start with a Hello World template:

src/main/resources/templates/pub/hello.html
<h1>Hello {http:param('name', 'Quarkus')}!</h1> (1)
1 {http:param('name', 'Quarkus')} é uma expressão que é exibida quando o modelo é renderizado (Quarkus é o valor padrão).
Os templates localizados no diretório pub são exibidos via HTTP. Esse comportamento é incorporado, não é necessário nenhum controller. Por exemplo, o template src/main/resources/templates/pub/foo.html será exibido a partir dos caminhos /foo e /foo.html por padrão.

Quando o aplicativo estiver em execução, você pode abrir o navegador e navegar para: http://localhost:8080/hello?name=Martin

For more information about Qute Web options, see the Qute Web guide.

Hello Qute and REST

Para um controle mais refinado, você pode combinar o Qute Web com o Quarkus REST (antigo RESTEasy Reactive) ou com a extensão baseada no RESTEasy Classic para controlar como o seu template será exbido

Using the quarkus-rest-qute extension:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-rest-qute</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-rest-qute")

A very simple text template:

hello.txt
Hello {name}! (1)
1 {name} é uma expressão de valor que é avaliada quando o modelo é processado.

Agora vamos injetar o modelo "compilado" na classe de recurso.

HelloResource.java
package org.acme.quarkus.sample;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import io.quarkus.qute.TemplateInstance;
import io.quarkus.qute.Template;

@Path("hello")
public class HelloResource {

    @Inject
    Template hello; (1)

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public TemplateInstance get(@QueryParam("name") String name) {
        return hello.data("name", name); (2) (3)
    }
}
1 Se não for fornecido um qualificador @Location, o nome do campo é utilizado para localizar o template. Neste caso específico, vamos injetar um template com o caminho templates/hello.txt.
2 O Template.data() retorna uma nova instância do template que pode ser configurado antes da renderização. Neste caso, colocamos o valor do nome na chave name. O mapa de dados é acessível durante a renderização.
3 Note that we don’t trigger the rendering - this is done automatically by a special ContainerResponseFilter implementation provided by quarkus-rest-qute.

Se sua aplicação estiver rodando, você pode fazer uma requisição ao endpoint:

$ curl -w "\n" http://localhost:8080/hello?name=Martin
Hello Martin!

Type-safe templates(Templates com tipos seguros)

Existe uma forma alternativa de declarar os seus modelos no seu código Java, que se baseia na seguinte convenção:

  • Organize seus arquivos de template no diretório /src/main/resources/templates , agrupando-os em um diretório por classe de recurso. Portanto, se a classe FruitResource fizer referência a dois templates: apples e oranges , coloque-os em /src/main/resources/templates/FruitResource/apples.txt e /src/main/resources/templates/FruitResource/oranges.txt . O agrupamento de templates por classe de recurso facilita a navegação até eles.

  • Em cada uma das suas classes de recursos, declare uma classe @CheckedTemplate static class Template {} dentro da sua classe de recursos.

  • Declare um public static native TemplateInstance method(); por arquivo template para o seu recurso.

  • Utilize esses métodos estáticos para criar as suas instâncias de template.

Aqui está o exemplo anterior, reescrito com este estilo:

Vamos começar com um modelo muito simples:

HelloResource/hello.txt
Hello {name}! (1)
1 {name} é uma expressão de valor que é avaliada quando o modelo é processado.

Now let’s declare and use this template in the resource class.

HelloResource.java
package org.acme.quarkus.sample;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import io.quarkus.qute.TemplateInstance;
import io.quarkus.qute.CheckedTemplate;

@Path("hello")
public class HelloResource {

    @CheckedTemplate
    public static class Templates {
        public static native TemplateInstance hello(String name); (1)
    }

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public TemplateInstance get(@QueryParam("name") String name) {
        return Templates.hello(name); (2)
    }
}
1 Isto declara um modelo com o caminho templates/HelloResource/hello.
2 Templates.hello() retorna uma nova instância do template que é retornada do método resource. Observe que não acionamos a renderização - isso é feito automaticamente por uma implementação especial do ContainerResponseFilter fornecida pelo quarkus-rest-qute .
Depois de declarar uma classe @CheckedTemplate, verificaremos se todos os seus métodos apontam para modelos existentes, por isso, informaremos no tempo de compilação, caso tenha esquecido de adicionar um template no seu projeto :)

Não se esqueça de que este estilo de declaração também permite fazer referência a templates declarados em outros recursos:

GreetingResource.java
package org.acme.quarkus.sample;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import io.quarkus.qute.TemplateInstance;

@Path("greeting")
public class GreetingResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public TemplateInstance get(@QueryParam("name") String name) {
        return HelloResource.Templates.hello(name);
    }
}

Templates e Níveis superiores.

Naturalmente, se quiser declarar os templates a um nível acima, você pode por exemplo, declará-los numa classe Templates de nível acima (não aninhada) diretamente em: /src/main/resources/templates/hello.txt

HelloResource.java
package org.acme.quarkus.sample;

import io.quarkus.qute.TemplateInstance;
import io.quarkus.qute.Template;
import io.quarkus.qute.CheckedTemplate;

@CheckedTemplate
public class Templates {
    public static native TemplateInstance hello(String name); (1)
}
1 Isto declara um template com o caminho templates/hello.

Declarações de parâmetros de modelo

Se você declarar uma declaração de parâmetro em um template, o Qute tentará validar todas as expressões que fazem referência a esse parâmetro e, se uma expressão incorreta for encontrada, a compilação falhará.

Vamos supor que temos uma classe simples como esta:

Item.java
public class Item {
    public String name;
    public BigDecimal price;
}

E gostaríamos de renderizar uma página HTML simples que contenha o nome e o preço do item.

Vamos começar de novo com o template:

ItemResource/item.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{item.name}</title> (1)
</head>
<body>
    <h1>{item.name}</h1>
    <div>Price: {item.price}</div> (2)
</body>
</html>
1 Esta expressão é validada. Se tentar alterar a expressão para {item.nonSense}, a construção deverá falhar.
2 Isto também é validado.

Finalmente, vamos criar uma classe de recurso com modelos type-safe:

ItemResource.java
package org.acme.quarkus.sample;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import io.quarkus.qute.TemplateInstance;
import io.quarkus.qute.Template;
import io.quarkus.qute.CheckedTemplate;

@Path("item")
public class ItemResource {

    @CheckedTemplate
    public static class Templates {
        public static native TemplateInstance item(Item item); (1)
    }

    @GET
    @Path("{id}")
    @Produces(MediaType.TEXT_HTML)
    public TemplateInstance get(@PathParam("id") Integer id) {
        return Templates.item(service.findItem(id)); (2)
    }
}
1 Declare um método que nos dê um TemplateInstance para templates/ItemResource/item.html e declare o seu parâmetro Item item para podermos validar o modelo.
2 Tornar o objeto Item acessível no template.
When the --parameters compiler argument is enabled, Quarkus REST may infer the parameter names from the method argument names, making the @PathParam("id") annotation optional in this case.

Declaração do parâmetro do template dentro do próprio template

Em alternativa, pode declarar os seus parâmetros de template no próprio arquivo de template.

Vamos começar de novo com o template:

item.html
{@org.acme.Item item} (1)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{item.name}</title> (2)
</head>
<body>
    <h1>{item.name}</h1>
    <div>Price: {item.price}</div>
</body>
</html>
1 Declaração de parâmetro opcional. O Qute tenta validar todas as expressões que fazem referência ao parâmetro item.
2 Esta expressão é validada. Se tentar alterar a expressão para {item.nonSense}, a construção deverá falhar.

Finalmente, vamos criar uma classe de recurso.

ItemResource.java
package org.acme.quarkus.sample;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import io.quarkus.qute.TemplateInstance;
import io.quarkus.qute.Template;

@Path("item")
public class ItemResource {

    @Inject
    ItemService service;

    @Inject
    Template item; (1)

    @GET
    @Path("{id}")
    @Produces(MediaType.TEXT_HTML)
    public TemplateInstance get(Integer id) {
        return item.data("item", service.findItem(id)); (2)
    }
}
1 Injetar o template com o caminho templates/item.html.
2 Tornar o objeto Item acessível no template.

Métodos de extensão de templates

Os métodos de extensão de templates são utilizados para estender o conjunto de propriedades acessíveis dos objetos de dados.

Às vezes, o usuário não tem controle sobre as classes que deseja usar no template e não pode adicionar métodos a elas. Os métodos de extensão de template permitem que você declare novos métodos para essas classes que estarão disponíveis nos templates, como se pertencessem à classe de destino.

Vamos continuar a estender a nossa página HTML simples que contém o nome do item, o preço e adicionar um preço com desconto. O preço com desconto é por vezes designado por “propriedade computada”. Vamos implementar um método de extensão de template para processar esta propriedade facilmente. Vamos atualizar o nosso template:

HelloResource/item.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{item.name}</title>
</head>
<body>
    <h1>{item.name}</h1>
    <div>Price: {item.price}</div>
    {#if item.price > 100} (1)
    <div>Discounted Price: {item.discountedPrice}</div> (2)
    {/if}
</body>
</html>
1 if é uma instrução básica do fluxo de controle.
2 Esta expressão é também validada em relação à classe Item e, obviamente, não existe tal propriedade declarada. No entanto, existe um método de extensão de template declarado na classe TemplateExtensions - veja abaixo.

Finalmente, vamos criar uma classe onde colocamos todos os nossos métodos de extensão:

TemplateExtensions.java
package org.acme.quarkus.sample;

import io.quarkus.qute.TemplateExtension;

@TemplateExtension
public class TemplateExtensions {

    public static BigDecimal discountedPrice(Item item) { (1)
        return item.price.multiply(new BigDecimal("0.9"));
    }
}
1 Um método de extensão de template estático pode ser utilizado para adicionar “propriedades computadas” a uma classe de dados. A classe do primeiro parâmetro é utilizada para corresponder ao objeto base e o nome do método é utilizado para corresponder ao nome da propriedade.
pode colocar métodos de extensão de templates em todas as classes se os anotar com @TemplateExtension, mas aconselhamos a mantê-los agrupados por tipo de destino ou numa única classe TemplateExtensions por convenção.

Renderização de relatórios periódicos

O mecanismo de templates também pode ser muito útil para renderizar relatórios periódicos. Primeiro, você precisará adicionar as extensões quarkus-scheduler e quarkus-qute . Em seu arquivo pom.xml , adicione:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-qute</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-scheduler</artifactId>
</dependency>

Vamos supor que temos um bean SampleService cujo método get() devolve uma lista de amostras.

Sample.java
public class Sample {
    public boolean valid;
    public String name;
    public String data;
}

O modelo é simples:

report.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Report {now}</title>
</head>
<body>
    <h1>Report {now}</h1>
    {#for sample in samples} (1)
      <h2>{sample.name ?: 'Unknown'}</h2> (2)
      <p>
      {#if sample.valid}
        {sample.data}
      {#else}
        <strong>Invalid sample found</strong>.
      {/if}
      </p>
    {/for}
</body>
</html>
1 A instrução de repetição permite iterar sobre iteráveis, mapas e fluxos.
2 Esta expressão de valor está utilizando o operador el vis - se o nome for nulo, é utilizado o valor predefinido.
ReportGenerator.java
package org.acme.quarkus.sample;

import jakarta.inject.Inject;

import io.quarkus.qute.Template;
import io.quarkus.qute.Location;
import io.quarkus.scheduler.Scheduled;

public class ReportGenerator {

    @Inject
    SampleService service;

    @Location("reports/v1/report_01") (1)
    Template report;

    @Scheduled(cron="0 30 * * * ?") (2)
    void generate() {
        String result = report
            .data("samples", service.get())
            .data("now", java.time.LocalDateTime.now())
            .render(); (3)
        // Write the result somewhere...
    }
}
1 Neste caso, utilizamos o qualificador @Location para especificar o caminho do template: templates/reports/v1/report_01.html.
2 Utilize a anotação @Scheduled para instruir o Quarkus a executar este método a cada meia hora. Para mais informações, consulte o guia Scheduler.
3 O método TemplateInstance.render() aciona a renderização. Note-se que este método bloqueia a thread atual.

Guia de Referência do Qute

Para saber mais sobre a Qute, consulte o guia de referência da Qute.

Referência de configuração do Qute

Propriedade de Configuração Fixa no Momento da Compilação - Todas as outras propriedades de configuração podem ser sobrepostas em tempo de execução.

Configuration property

Tipo

Padrão

The list of suffixes used when attempting to locate a template file.

By default, engine.getTemplate("foo") would result in several lookups: foo, foo.html, foo.txt, etc.

Environment variable: QUARKUS_QUTE_SUFFIXES

Show more

list of string

qute.html, qute.txt, html, txt

The additional map of suffixes to content types. This map is used when working with template variants. By default, the java.net.URLConnection#getFileNameMap() is used to determine the content type of a template file.

Environment variable: QUARKUS_QUTE_CONTENT_TYPES__FILE_SUFFIX_

Show more

Map<String,String>

The list of exclude rules used to intentionally ignore some parts of an expression when performing type-safe validation.

An element value must have at least two parts separated by dot. The last part is used to match the property/method name. The prepended parts are used to match the class name. The value * can be used to match any name.

Examples:

  • org.acme.Foo.name - exclude the property/method name on the org.acme.Foo class

  • org.acme.Foo.* - exclude any property/method on the org.acme.Foo class

  • *.age - exclude the property/method age on any class

Environment variable: QUARKUS_QUTE_TYPE_CHECK_EXCLUDES

Show more

list of string

This regular expression is used to exclude template files found in template roots. Excluded templates are neither parsed nor validated during build and are not available at runtime.

The matched input is the file path relative from the root directory and the / is used as a path separator.

By default, the hidden files are excluded. The name of a hidden file starts with a dot.

Environment variable: QUARKUS_QUTE_TEMPLATE_PATH_EXCLUDE

Show more

Pattern

^\..*|.*\/\..*$

The prefix is used to access the iteration metadata inside a loop section.

A valid prefix consists of alphanumeric characters and underscores. Three special constants can be used:

  • <alias_> - the alias of an iterated element suffixed with an underscore is used, e.g. item_hasNext and it_count

  • <alias?> - the alias of an iterated element suffixed with a question mark is used, e.g. item?hasNext and it?count

  • <none> - no prefix is used, e.g. hasNext and count

By default, the <alias_> constant is set.

Environment variable: QUARKUS_QUTE_ITERATION_METADATA_PREFIX

Show more

string

The list of content types for which the ', ", <, > and & characters are escaped if a template variant is set.

Environment variable: QUARKUS_QUTE_ESCAPE_CONTENT_TYPES

Show more

list of string

text/html, text/xml, application/xml, application/xhtml+xml

The default charset of the templates files.

Environment variable: QUARKUS_QUTE_DEFAULT_CHARSET

Show more

Charset

UTF-8

The strategy used when multiple templates with the same path are found in the application.

Environment variable: QUARKUS_QUTE_DUPLICIT_TEMPLATES_STRATEGY

Show more

prioritizeIf multiple templates with the same path are found then determine the highest priority value and eliminate all templates with lowest priority. If there is exactly one template remaining then use this template. Otherwise, fail the build. Templates from the root application archive have the priority 30. Templates from other application archives have the priority 10. Templates from build items can define any priority., failFail the build if multiple templates with the same path are found.

prioritizeIf multiple templates with the same path are found then determine the highest priority value and eliminate all templates with lowest priority. If there is exactly one template remaining then use this template. Otherwise, fail the build. Templates from the root application archive have the priority {@code 30}. Templates from other application archives have the priority {@code 10}. Templates from build items can define any priority.

Use the equals character as a command to identify an output expression in all templates from the application template root, i.e. src/main/resources/templates.

By default, no special command is used, i.e. the syntax for an output expression looks like {foo.name}. If set to true then the equals command is used instead. The alternative syntax looks like {=foo.name}.

Environment variable: QUARKUS_QUTE_ALT_EXPR_SYNTAX

Show more

booleano

false

By default, a template modification results in an application restart that triggers build-time validations.

This regular expression can be used to specify the templates for which the application is not restarted. I.e. the templates are reloaded and only runtime validations are performed.

The matched input is the template path that starts with a template root, and the / is used as a path separator. For example, templates/foo.html.

Environment variable: QUARKUS_QUTE_DEV_MODE_NO_RESTART_TEMPLATES

Show more

Pattern

By default, the rendering results of injected and type-safe templates are recorded in the managed RenderedResults which is registered as a CDI bean.

Environment variable: QUARKUS_QUTE_TEST_MODE_RECORD_RENDERED_RESULTS

Show more

booleano

true

Enables or disables the Qute debug mode. This feature is experimental.

When enabled, Qute templates can be debugged directly at runtime. This includes the ability to:

  • Set breakpoints inside templates

  • Inspect the stack trace of visited template nodes during rendering

  • Evaluate expressions in the current Qute context

This mode is intended for development and troubleshooting purposes.

Default value: true

Example configuration:

quarkus.qute.debug.enabled = false

Environment variable: QUARKUS_QUTE_DEBUG_ENABLED

Show more

booleano

true

The strategy used when a standalone expression evaluates to a "not found" value at runtime and the quarkus.qute.strict-rendering config property is set to false

This strategy is never used when evaluating section parameters, e.g. {#if foo.name}. In such case, it’s the responsibility of the section to handle this situation appropriately.

By default, the NOT_FOUND constant is written to the output. However, in the development mode the PropertyNotFoundStrategy#THROW_EXCEPTION is used by default, i.e. when the strategy is not specified.

Environment variable: QUARKUS_QUTE_PROPERTY_NOT_FOUND_STRATEGY

Show more

defaultOutput the NOT_FOUND constant., noopNo operation - no output., throw-exceptionThrow a TemplateException., output-originalOutput the original expression string, e.g. {foo.name}.

Specify whether the parser should remove standalone lines from the output. A standalone line is a line that contains at least one section tag, parameter declaration, or comment but no expression and no non-whitespace character.

Environment variable: QUARKUS_QUTE_REMOVE_STANDALONE_LINES

Show more

booleano

true

If set to true then any expression that is evaluated to a Results.NotFound value will always result in a TemplateException and the rendering is aborted.

Note that the quarkus.qute.property-not-found-strategy config property is completely ignored if strict rendering is enabled.

Environment variable: QUARKUS_QUTE_STRICT_RENDERING

Show more

booleano

true

The global rendering timeout in milliseconds. It is used if no timeout template instance attribute is set.

Environment variable: QUARKUS_QUTE_TIMEOUT

Show more

long

10000

If set to true then the timeout should also be used for asynchronous rendering methods, such as TemplateInstance#createUni() and TemplateInstance#renderAsync().

Environment variable: QUARKUS_QUTE_USE_ASYNC_TIMEOUT

Show more

booleano

true

Related content