Pular para o conteúdo principal

Aula 11: Introdução ao Jakarta Faces com Quarkus

Objetivos

  • Compreender o que é Jakarta Faces e seu papel no ecossistema Jakarta EE
  • Dominar os conceitos de componentes, Managed Beans, ciclo de vida e Facelets
  • Integrar Jakarta Faces com Quarkus 3.31 para aplicações cloud-native
  • Utilizar PrimeFaces para componentes visuais ricos e modernos
  • Implementar uma aplicação de saudação completa, do zero ao deploy

Conteúdo

Contexto e Motivação

O desenvolvimento de aplicações web Java passou por diversas transformações ao longo das últimas décadas. Entre os frameworks mais tradicionais, o Jakarta Faces (antigo JSF — JavaServer Faces) se destaca por oferecer uma abordagem baseada em componentes para construção de interfaces ricas e dinâmicas. Com a ascensão do Quarkus, um framework moderno e otimizado para cloud-native, surge a oportunidade de unir o poder do Jakarta Faces à agilidade e leveza do Quarkus.

A escolha por Jakarta Faces não é apenas uma questão de tradição, mas de estratégia. Muitas empresas mantêm sistemas críticos em JSF, e migrar para soluções modernas pode ser caro e arriscado. Integrar JSF ao Quarkus permite modernizar gradualmente, aproveitando o que há de melhor em ambos os mundos: a robustez do JSF e a performance do Quarkus.

observação

Jakarta Faces é amplamente utilizado em sistemas legados e corporativos. Aprender a integrá-lo ao Quarkus é estratégico para profissionais que desejam atuar em projetos de modernização.

Além disso, o mercado exige cada vez mais aplicações escaláveis, rápidas e preparadas para cloud. Quarkus foi criado para atender a essas demandas, e sua integração com Jakarta Faces permite que equipes aproveitem o conhecimento já existente em JSF, sem prescindir das vantagens do desenvolvimento cloud-native.

VantagemExplicação
Modernização GradualPermite atualizar sistemas sem reescrever tudo do zero
PerformanceQuarkus reduz tempo de inicialização e uso de memória
Cloud-ReadyFacilita o deploy em containers e ambientes cloud
ReaproveitamentoUtiliza o conhecimento e código JSF já existente
cuidado

Muitos desenvolvedores acreditam que JSF está obsoleto, mas grandes empresas e órgãos públicos ainda dependem fortemente desse framework. Saber integrá-lo ao Quarkus é um diferencial competitivo.


O que é Jakarta Faces?

Jakarta Faces é um framework MVC (Model-View-Controller) para construção de interfaces web em Java. Ele utiliza páginas XHTML como "View", beans gerenciados como "Model" e um ciclo de vida próprio para processar requisições e respostas.

Por que MVC? O padrão MVC separa a lógica de apresentação (View), a lógica de negócio (Model) e o controle do fluxo (Controller), facilitando manutenção, testes e evolução do sistema.

Principais conceitos:

  • Componentes: Elementos reutilizáveis (botões, tabelas, formulários) definidos em XHTML. Cada componente JSF encapsula comportamento e aparência, facilitando a criação de interfaces ricas sem depender de JavaScript.
  • Managed Beans: Classes Java que representam dados e lógica de negócio, integradas à interface. São gerenciados pelo contêiner, permitindo injeção de dependências e controle de ciclo de vida.
  • Ciclo de Vida: Sequência de fases que processa requisições, valida dados, atualiza modelos e renderiza respostas. O ciclo de vida JSF garante que dados sejam validados e processados antes de serem exibidos ou persistidos.
  • Facelets: Sistema de templates que facilita a composição de páginas. Permite criar layouts reutilizáveis e organizar o código XHTML de forma modular.
TermoDefinição
ComponentesElementos visuais reutilizáveis definidos em XHTML
Managed BeansClasses Java que representam dados e lógica
Ciclo de VidaFases de processamento de requisições JSF
FaceletsSistema de templates para páginas JSF
dica

O ciclo de vida do JSF é composto por seis fases principais: restauração da árvore de componentes, aplicação de valores de requisição, processamento de eventos, validação, atualização do modelo e renderização da resposta. Cada fase pode ser interceptada para customizar o comportamento da aplicação.


Por que usar com Quarkus?

Quarkus traz diversos benefícios importantes para o desenvolvimento moderno de aplicações Java. Em primeiro lugar, oferece inicialização ultrarrápida que reduz drasticamente o tempo de startup das aplicações. Além disso, apresenta baixo consumo de memória, tornando as aplicações mais eficientes em termos de recursos. O framework também traz suporte nativo a containers e cloud, facilitando o deploy em ambientes modernos. Por fim, possui integração facilitada com CDI, JPA e outros padrões Jakarta EE.

A combinação de Jakarta Faces com Quarkus resulta em diversos benefícios: interfaces ricas e reativas, backend moderno, leve e escalável, e grande facilidade de integração com APIs REST, microserviços e persistência de dados.

important

A integração entre Jakarta Faces e Quarkus permite que aplicações legadas ganhem performance e estejam prontas para ambientes cloud-native.

CaracterísticaJSF TradicionalJSF com Quarkus
InicializaçãoLentaRápida
Consumo de MemóriaAltoBaixo
Deploy em CloudComplexoSimples (Docker/Kubernetes)
Integração com APIsLimitadaFacilitada
observação

Quarkus foi projetado para funcionar bem com GraalVM, permitindo compilar aplicações desenvolvidas utilizando Java em binários nativos. Isso reduz drasticamente o tempo de inicialização e o consumo de recursos, tornando JSF viável até para microserviços.


Exercícios (Checkpoints)

Laboratório 6 — Jakarta Faces com Quarkus

Nesta seção, vamos construir uma aplicação de cadastro de usuários utilizando Jakarta Faces com Quarkus, detalhando cada etapa e explicando o propósito de cada decisão técnica.

Passo 1: Configuração do Projeto

A configuração inicial é fundamental para garantir que todos os recursos do Quarkus e do PrimeFaces estejam disponíveis. O PrimeFaces oferece componentes visuais muito mais ricos que o JSF básico, facilitando a criação de interfaces modernas e responsivas.

Para a criação do projeto, utilize o Maven com o plugin do Quarkus indicando a extensão do PrimeFaces:

mvn io.quarkus.platform:quarkus-maven-plugin:3.31.0:create \
-DprojectGroupId=com.exemplo \
-DprojectArtifactId=faces-quarkus \
-Dextensions="quarkus-primefaces"

Vamos utilizar o projeto desenvolvido no laboratório anterior como base, adicionando as dependências e configurações necessárias para o JSF.

No arquivo pom.xml, inclua as dependências do PrimeFaces para Quarkus 3. Isso garante que todos os componentes avançados estejam disponíveis:

<dependency>
<groupId>io.quarkiverse.primefaces</groupId>
<artifactId>quarkus-primefaces</artifactId>
<version>3.15.7</version>
</dependency>
<dependency>
<groupId>io.quarkiverse.primefaces</groupId>
<artifactId>quarkus-primefaces-extensions</artifactId>
<version>3.15.7</version>
</dependency>
important

O PrimeFaces 3.15.7 é a versão mais atual e compatível com Quarkus 3, oferecendo componentes Ajax, gráficos, calendários e muito mais, prontos para uso.

Passo 2: Estrutura de Diretórios

Organizar os arquivos é essencial para facilitar a manutenção e evolução do projeto. No Quarkus, a estrutura de diretórios segue algumas convenções específicas que diferem ligeiramente do Jakarta EE tradicional.

Por que a estrutura de diretórios é importante? Uma organização adequada dos arquivos facilita a localização de componentes, simplifica a manutenção e permite que novos desenvolvedores compreendam rapidamente o projeto. No Quarkus, algumas convenções específicas garantem que os recursos sejam carregados corretamente.

Estrutura Recomendada para Quarkus + Jakarta Faces
src/
├── main/
│ ├── java/
│ │ └── br/upf/ads175/critiquehub/
│ │ ├── presentation/
│ │ │ ├── Saudacao.java # Bean de modelo
│ │ │ └── SaudacaoManagedBean.java # Bean gerenciado
│ │ └── service/
│ │ └── SaudacaoService.java # Serviços de negócio
│ ├── resources/
│ │ ├── META-INF/
│ │ │ └── resources/ # Recursos web do Quarkus
│ │ │ ├── index.xhtml # Página principal
│ │ │ ├── sobre.xhtml # Página sobre
│ │ │ └── css/
│ │ │ └── app.css # Estilos customizados
│ │ └── application.properties # Configurações da aplicação
│ └── webapp/
│ └── WEB-INF/
│ └── web.xml # Configuração JSF
└── test/
└── java/
└── br/upf/ads175/critiquehub/
└── presentation/
└── SaudacaoManagedBeanTest.java # Testes unitários
Detalhamento dos Diretórios
DiretórioPropósitoObservações
presentation/Beans de modelo e gerenciados (camada de apresentação)Contém classes que interagem diretamente com a interface JSF
service/Serviços de negócio e lógica de aplicaçãoClasses com anotações CDI (@ApplicationScoped, @RequestScoped)
META-INF/resources/Páginas XHTML e recursos estáticos (específico do Quarkus)Crucial: No Quarkus, páginas web devem estar aqui, não em webapp
webapp/WEB-INF/Configurações do Jakarta FacesContém web.xml e outras configurações específicas do JSF
resources/Arquivos de configuração da aplicaçãoapplication.properties, resources para templates, etc.
observação

Diferença Importante: No Quarkus, as páginas XHTML devem estar em src/main/resources/META-INF/resources/ e não em src/main/webapp/. Esta é uma convenção específica do Quarkus para servir recursos estáticos.

Convenções de Nomenclatura

Para manter consistência com o projeto CritiqueHub, seguiremos estas convenções:

  • Pacotes: Usar o padrão br.upf.ads175.critiquehub.{camada}
  • Beans de Modelo: Nomes simples (ex: Saudacao, Usuario)
  • Beans Gerenciados: Sufixo ManagedBean (ex: SaudacaoManagedBean)
  • Serviços: Sufixo Service (ex: SaudacaoService)
  • Páginas XHTML: Nomes descritivos em minúsculas (ex: index.xhtml, sobre.xhtml)
dica

Dica de Organização: Mantenha a separação clara entre as camadas:

  • presentation/: Tudo relacionado à interface (beans JSF)
  • service/: Lógica de negócio e serviços
  • model/ ou entity/: Entidades de domínio (quando usar JPA)
  • repository/: Acesso a dados (quando usar JPA)
cuidado

Atenção: Se você colocar as páginas XHTML em src/main/webapp/ (como no Jakarta EE tradicional), elas não serão servidas corretamente pelo Quarkus. Sempre use src/main/resources/META-INF/resources/ para recursos web no Quarkus.

Passo 3: Criando o Bean de Modelo

O bean de modelo Saudacao representa os dados da saudação. Ele possui dois atributos: nome e mensagem, ambos com métodos getter e setter para permitir o binding (vinculação) com os componentes JSF.

O que é binding? É o mecanismo que conecta automaticamente os campos da interface com os atributos dos beans Java, permitindo que mudanças em um sejam refletidas no outro.

// Saudacao.java
package br.upf.ads175.critiquehub.presentation;

/**
* Bean de modelo para armazenar dados da saudação.
* Este é um POJO (Plain Old Java Object) simples que representa
* os dados que serão manipulados na interface.
*/
public class Saudacao {
private String nome; // Nome do usuário
private String mensagem; // Mensagem de saudação

/**
* Construtor padrão necessário para JSF
*/
public Saudacao() {
// Construtor vazio obrigatório
}

// Getter e setter para nome
public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}

// Getter e setter para mensagem
public String getMensagem() {
return mensagem;
}

public void setMensagem(String mensagem) {
this.mensagem = mensagem;
}

/**
* Método auxiliar para exibição formatada
*/
public String getSaudacaoCompleta() {
if (nome != null && mensagem != null &&
!nome.trim().isEmpty() && !mensagem.trim().isEmpty()) {
return nome + ", " + mensagem;
}
return "";
}
}
dica

Os métodos getter e setter seguem a convenção JavaBeans, que é essencial para que o JSF consiga acessar e modificar os dados automaticamente através do Expression Language (EL).

Passo 4: Bean Gerenciado

O bean gerenciado SaudacaoManagedBean controla o ciclo de vida da saudação e expõe métodos para manipulação dos dados. Este é o Controller no padrão MVC.

// SaudacaoManagedBean.java
package br.upf.ads175.critiquehub.presentation;

import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named;

/**
* Bean gerenciado para interação com a interface JSF.
* A anotação @Named torna este bean acessível via Expression Language (EL).
* A anotação @RequestScoped define que uma nova instância será criada
* a cada requisição HTTP.
*/
@Named
@RequestScoped
public class SaudacaoManagedBean {

private Saudacao saudacao = new Saudacao(); // Instância do modelo

/**
* Getter para o modelo.
* Este método é chamado pelo JSF quando #{saudacaoManagedBean.saudacao}
* é usado na página XHTML.
*/
public Saudacao getSaudacao() {
return saudacao;
}

/**
* Método para limpar os campos do formulário.
* Cria uma nova instância de Saudacao, efetivamente
* limpando todos os campos.
*/
public void limpar() {
saudacao = new Saudacao();
System.out.println("Formulário limpo"); // Log para debug
}

/**
* Método para demonstrar processamento de dados.
* Em uma aplicação real, aqui seria feita a persistência
* ou chamada de serviços de negócio.
*/
public void processar() {
System.out.println("Processando saudação: " + saudacao.getSaudacaoCompleta());
}
}
observação

O escopo @RequestScoped significa que o bean existe apenas durante uma requisição HTTP. Para dados que precisam persistir entre requisições, use @SessionScoped ou @ViewScoped.

Passo 5: Página XHTML

A página index.xhtml define o formulário de saudação, vinculando os campos ao bean gerenciado. O uso de <f:ajax> permite atualização parcial da interface sem recarregar a página inteira.

Por que usar AJAX? O AJAX (Asynchronous JavaScript and XML) permite uma experiência mais fluida, atualizando apenas partes específicas da página em resposta às ações do usuário.

<!-- index.xhtml -->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>CritiqueHub - Aplicação de Saudação</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.form-group { margin: 10px 0; }
.form-group label { display: inline-block; width: 100px; }
.form-group input { width: 200px; padding: 5px; }
.buttons { margin: 20px 0; }
.buttons button { margin-right: 10px; padding: 8px 16px; }
.output { margin-top: 20px; padding: 10px; background: #f5f5f5; }
</style>
</h:head>
<h:body>
<h1>Aplicação de Saudação JSF</h1>

<h:form id="saudacaoForm">
<!-- Campo para nome -->
<div class="form-group">
<h:outputLabel value="Nome:" for="nome"/>
<h:inputText id="nome"
value="#{saudacaoManagedBean.saudacao.nome}"
placeholder="Digite seu nome"/>
</div>

<!-- Campo para mensagem -->
<div class="form-group">
<h:outputLabel value="Mensagem:" for="mensagem"/>
<h:inputText id="mensagem"
value="#{saudacaoManagedBean.saudacao.mensagem}"
placeholder="Digite sua mensagem"/>
</div>

<!-- Botões de ação -->
<div class="buttons">
<!-- Botão para atualizar saudação -->
<h:commandButton value="Atualizar" styleClass="btn-primary">
<f:ajax execute="@form" render="saudacaoAtual"/>
</h:commandButton>

<!-- Botão para limpar campos -->
<h:commandButton value="Limpar"
action="#{saudacaoManagedBean.limpar}"
styleClass="btn-secondary">
<f:ajax execute="@form" render="@form"/>
</h:commandButton>

<!-- Botão para processar (demonstração) -->
<h:commandButton value="Processar"
action="#{saudacaoManagedBean.processar}"
styleClass="btn-success">
<f:ajax execute="@form" render="@none"/>
</h:commandButton>
</div>

<!-- Exibição da saudação atual -->
<div class="output">
<h:outputLabel value="Saudação Atual:" />
<h:outputText id="saudacaoAtual"
value="#{saudacaoManagedBean.saudacao.saudacaoCompleta}"
style="font-weight: bold; color: #2c5aa0;"/>
</div>
</h:form>

<!-- Informações de debug (apenas em desenvolvimento) -->
<div style="margin-top: 30px; font-size: 12px; color: #666;">
<h3>Informações de Debug:</h3>
<p>Bean Scope: Request Scoped</p>
<p>Nome atual: #{saudacaoManagedBean.saudacao.nome}</p>
<p>Mensagem atual: #{saudacaoManagedBean.saudacao.mensagem}</p>
</div>
</h:body>
</html>
dica

O atributo execute="@form" faz com que todos os campos do formulário sejam enviados para o servidor, enquanto render="saudacaoAtual" atualiza apenas o elemento especificado.

Passo 6: Configuração Faces

A configuração do Faces Servlet no web.xml é obrigatória para que o JSF funcione corretamente. Ela define o mapeamento das páginas e o modo de operação do framework.

<!-- web.xml -->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
version="4.0">

<!-- Configuração do estágio de projeto (Development/Production) -->
<context-param>
<param-name>jakarta.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>

<!-- Habilita estado de vista no cliente para melhor performance -->
<context-param>
<param-name>jakarta.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>

<!-- Configuração do Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<!-- Mapeamento para processar arquivos .xhtml -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>

<!-- Define a página inicial -->
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>

<!-- Configuração de timeout de sessão -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>
important

A configuração PROJECT_STAGE como "Development" habilita mensagens de erro detalhadas e recursos de debug. Em produção, altere para "Production".

Passo 7: Executando a Aplicação

Para executar a aplicação, use o comando do Quarkus:

./mvnw quarkus:dev

A aplicação estará disponível em http://localhost:8080 e você verá:

  1. Campos de entrada: Nome e Mensagem
  2. Botão Atualizar: Mostra a saudação sem recarregar a página
  3. Botão Limpar: Limpa os campos usando AJAX
  4. Botão Processar: Demonstra ação do servidor
  5. Saída dinâmica: Mostra a saudação formatada
observação

O Quarkus dev mode permite alterações em tempo real. Modifique o código e veja as mudanças instantaneamente no navegador.


Laboratório 7 — Jakarta Faces com PrimeFaces e Quarkus

Nesta seção, vamos construir uma aplicação simples de saudação utilizando Jakarta Faces com PrimeFaces e Quarkus, demonstrando os componentes básicos mais ricos que o JSF core tradicional.

Passo 1: Configuração do Projeto com PrimeFaces

Para criar o projeto, utilize o Maven com o plugin do Quarkus:

mvn io.quarkus.platform:quarkus-maven-plugin:3.31.0:create \
-DprojectGroupId=br.upf.ads175.critiquehub \
-DprojectArtifactId=faces-primefaces-basic \
-Dextensions="quarkus-primefaces"
important

A extensão quarkus-primefaces já inclui automaticamente o Jakarta Faces e todas as dependências necessárias.

Caso esteja adicionando ao projeto existente, inclua a dependência no pom.xml:

<dependency>
<groupId>io.quarkiverse.primefaces</groupId>
<artifactId>quarkus-primefaces</artifactId>
<version>3.15.7</version>
</dependency>

Passo 2: Estrutura Simplificada

src/
├── main/
│ ├── java/
│ │ └── br/upf/ads175/critiquehub/
│ │ └── SaudacaoController.java # Bean gerenciado
│ ├── resources/
│ │ ├── META-INF/
│ │ │ └── resources/
│ │ │ └── index.xhtml # Página principal
│ │ └── application.properties
│ └── webapp/
│ └── WEB-INF/
│ └── web.xml # Configuração JSF

Passo 3: Bean Gerenciado

Vamos criar um bean simples para controlar a aplicação de saudação:

// SaudacaoController.java
package br.upf.ads175.critiquehub;

import jakarta.enterprise.context.RequestScoped;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.inject.Named;

/**
* Bean gerenciado para aplicação de saudação com PrimeFaces.
*/
@Named
@RequestScoped
public class SaudacaoController {

private String nome;
private String email;
private String mensagem = "";

/**
* Gera uma saudação personalizada.
*/
public void gerarSaudacao() {
if (nome != null && !nome.trim().isEmpty()) {
mensagem = "Olá, " + nome + "! Bem-vindo ao sistema CritiqueHub!";

if (email != null && !email.trim().isEmpty()) {
mensagem += " Seu email " + email + " foi registrado.";
}

// Adiciona mensagem de sucesso
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_INFO,
"Sucesso!",
"Saudação gerada com sucesso!"));
} else {
mensagem = "";
// Adiciona mensagem de erro
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR,
"Erro!",
"Por favor, digite seu nome!"));
}
}

/**
* Limpa todos os campos.
*/
public void limpar() {
nome = "";
email = "";
mensagem = "";

FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_INFO,
"Limpo!",
"Campos foram limpos!"));
}

// Getters e Setters
public String getNome() { return nome; }
public void setNome(String nome) { this.nome = nome; }

public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }

public String getMensagem() { return mensagem; }
public void setMensagem(String mensagem) { this.mensagem = mensagem; }

public boolean isMensagemVazia() {
return mensagem == null || mensagem.trim().isEmpty();
}
}

Passo 4: Página XHTML com PrimeFaces

Agora vamos criar uma página simples comparando JSF core com PrimeFaces:

<!-- index.xhtml -->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui">

<h:head>
<title>CritiqueHub - Exemplo PrimeFaces</title>
</h:head>

<h:body style="padding: 20px; font-family: Arial;">
<h:form id="form">

<!-- Cabeçalho com PrimeFaces -->
<p:panel header="CritiqueHub - Exemplo Básico PrimeFaces"
style="margin-bottom: 20px;">
<p>Este exemplo demonstra a diferença entre JSF core e PrimeFaces</p>
</p:panel>

<!-- Seção: Comparação JSF Core vs PrimeFaces -->
<p:tabView>

<!-- Aba 1: PrimeFaces -->
<p:tab title="Com PrimeFaces">
<h:panelGrid columns="2" cellpadding="10">

<!-- Campo nome com PrimeFaces -->
<p:outputLabel for="nomePrime" value="Nome:*"
style="font-weight: bold;"/>
<p:inputText id="nomePrime"
value="#{saudacaoController.nome}"
placeholder="Digite seu nome"
required="true"
requiredMessage="Nome é obrigatório"
style="width: 300px;"/>

<!-- Campo email com validação -->
<p:outputLabel for="emailPrime" value="Email:"
style="font-weight: bold;"/>
<p:inputText id="emailPrime"
value="#{saudacaoController.email}"
placeholder="seu@email.com"
style="width: 300px;">
<f:validateRegex
pattern="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
validatorMessage="Email inválido"/>
</p:inputText>

<!-- Botões com ícones -->
<h:outputText value="" />
<h:panelGroup>
<p:commandButton value="Gerar Saudação"
action="#{saudacaoController.gerarSaudacao}"
update="form"
icon="pi pi-check"
styleClass="ui-button-success"
style="margin-right: 10px;"/>

<p:commandButton value="Limpar"
action="#{saudacaoController.limpar}"
update="form"
icon="pi pi-refresh"
styleClass="ui-button-secondary"/>
</h:panelGroup>
</h:panelGrid>

<!-- Resultado com PrimeFaces -->
<p:panel header="Resultado"
rendered="#{!saudacaoController.mensagemVazia}"
style="margin-top: 20px; background-color: #f0f8ff;">
<h:outputText value="#{saudacaoController.mensagem}"
style="font-size: 16px; color: #2e8b57;"/>
</p:panel>
</p:tab>

<!-- Aba 2: JSF Core (para comparação) -->
<p:tab title="JSF Core Tradicional">
<p style="color: #666; font-style: italic; margin-bottom: 20px;">
Para comparação, veja como seria com JSF core:
</p>

<pre style="background: #f5f5f5; padding: 15px; border-radius: 5px;">
&lt;h:panelGrid columns="2"&gt;
&lt;h:outputLabel value="Nome:" /&gt;
&lt;h:inputText value="#{bean.nome}" /&gt;

&lt;h:outputLabel value="Email:" /&gt;
&lt;h:inputText value="#{bean.email}" /&gt;

&lt;h:commandButton value="Gerar" action="#{bean.gerar}" /&gt;
&lt;h:commandButton value="Limpar" action="#{bean.limpar}" /&gt;
&lt;/h:panelGrid&gt;

&lt;h:outputText value="#{bean.mensagem}"
rendered="#{!bean.mensagemVazia}" /&gt;
</pre>

<p:panel header="Limitações do JSF Core">
<ul>
<li>Sem validação visual automática</li>
<li>Campos simples sem placeholder</li>
<li>Botões sem ícones</li>
<li>Sem estilos modernos</li>
<li>Não responsivo</li>
<li>Sem componentes ricos (calendário, máscaras, etc.)</li>
</ul>
</p:panel>
</p:tab>

</p:tabView>

<!-- Demonstração de Componentes PrimeFaces -->
<p:panel header="Exemplos de Componentes PrimeFaces"
style="margin-top: 20px;">

<h:panelGrid columns="2" cellpadding="10">

<!-- Rating (Avaliação) -->
<p:outputLabel value="Avalie o exemplo:" style="font-weight: bold;"/>
<p:rating stars="5" cancel="false"/>

<!-- ProgressBar -->
<p:outputLabel value="Progresso:" style="font-weight: bold;"/>
<p:progressBar value="75"
labelTemplate="{value}% completo"
style="width: 300px;"/>

<!-- Switch/Toggle -->
<p:outputLabel value="Modo escuro:" style="font-weight: bold;"/>
<p:toggleSwitch value="false"/>

<!-- Chips (Tags) -->
<p:outputLabel value="Tecnologias:" style="font-weight: bold;"/>
<p:chips value="#{null}"
placeholder="Digite e pressione Enter"
style="width: 300px;"/>

</h:panelGrid>
</p:panel>

<!-- Mensagens do sistema -->
<p:messages autoUpdate="true" closable="true"
style="margin-top: 20px;"/>

</h:form>
</h:body>
</html>
dica

Componentes PrimeFaces demonstrados:

  • p:panel: Painéis com cabeçalho estilizado
  • p:tabView: Abas para organizar conteúdo
  • p:inputText: Campos com placeholder e validação visual
  • p:commandButton: Botões com ícones e estilos
  • p:messages: Sistema de mensagens elegante
  • p:rating: Componente de avaliação por estrelas
  • p:progressBar: Barra de progresso animada
  • p:toggleSwitch: Switch moderno
  • p:chips: Tags editáveis

Passo 5: Configuração Web.xml

<!-- web.xml -->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="4.0">

<!-- Modo desenvolvimento -->
<context-param>
<param-name>jakarta.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>

<!-- Tema PrimeFaces -->
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>nova-light</param-value>
</context-param>

<!-- Configuração Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
</web-app>

Passo 6: Executando a Aplicação

Execute o comando:

./mvnw quarkus:dev

Acesse http://localhost:8080 e você verá:

  1. Interface com Abas: Compare PrimeFaces vs JSF core
  2. Campos Melhorados: Com placeholder e validação visual
  3. Botões Estilizados: Com ícones e cores
  4. Componentes Ricos: Rating, progressBar, toggleSwitch
  5. Mensagens Elegantes: Feedback visual das ações
  6. Layout Responsivo: Painéis organizados
important

Vantagens do PrimeFaces demonstradas:

  1. Produtividade: Componentes prontos para uso
  2. Experiência do Usuário: Interface moderna e responsiva
  3. Validação: Feedback visual automático
  4. Manutenibilidade: Código mais limpo e organizado
  5. Flexibilidade: Fácil personalização de temas

Este laboratório mostra de forma prática como o PrimeFaces eleva significativamente a qualidade das interfaces JSF, oferecendo componentes modernos sem complexidade adicional no desenvolvimento.


Relacionamento do Jakarta Faces com Demais Tecnologias

O Jakarta Faces conecta-se com as demais tecnologias vistas anteriormente, servindo como ponte entre as demais camadas da aplicação. No ecossistema Quarkus + Jakarta EE, a camada de apresentação (Faces) consome serviços CDI, que por sua vez utilizam JPA/Panache para persistência, criando uma arquitetura coesa e bem definida.


Referências