5. Introdução à biblioteca de componentes PrimeFaces
5.1. O papel do Primefaces em um aplicativo JSF
Voltemos à arquitetura de um aplicativo JSF, tal como a estudamos no início deste documento:
![]() |
As páginas JSF foram construídas com três bibliotecas de tags:
- linha 2: as tags <h:x> do espaço de nomes [http://java.sun.com/jsf/html], que correspondem às tags HTML,
- linha 3: as tags <f:y> do espaço de nomes [http://java.sun.com/jsf/core], que correspondem às tags JSF,
- linha 4: as tags <ui:z> do espaço de nomes [http://java.sun.com/jsf/facelets], que correspondem às tags dos facelets.
Para construir as páginas JSF, vamos adicionar uma quarta biblioteca de tags, a dos componentes Primefaces.
- linha 3: as tags <p:z> do namespace [http://primefaces.org/ui] correspondem aos componentes Primefaces.
Essa é a única alteração que será exibida. Portanto, ela aparece nas visualizações. Os gerenciadores de eventos e os modelos permanecem os mesmos que eram com JSF. É importante compreender esse ponto.
O uso dos componentes Primefaces permite criar interfaces web mais intuitivas, graças aos diversos componentes dessa biblioteca, e mais fluidas, graças à tecnologia AJAX que ela utiliza nativamente. Fala-se, então, de interfaces ricas ou RIA (Rich Internet Application).
A arquitetura JSF anterior se tornará a arquitetura PF (Primefaces) a seguir:
![]() |
5.2. As contribuições do Primefaces
O site do Primefaces [http://www.primefaces.org/showcase/ui/home.jsf] apresenta a lista de componentes que podem ser utilizados em uma página PF:
![]() |
Nos exemplos a seguir, utilizaremos as duas primeiras funcionalidades do Primefaces:
- alguns dos cerca de cem componentes oferecidos,
- o comportamento nativo AJAX desses componentes.
Entre os componentes disponíveis:
![]() | ![]() | ![]() |
Usaremos apenas cerca de quinze deles em nossos exemplos, mas isso será suficiente para compreender os princípios de construção de uma página Primefaces.
5.3. Aprendizado do Primefaces
O Primefaces oferece exemplos de uso de cada um de seus componentes. Basta clicar no link correspondente. Vejamos um exemplo:
![]() |
- em [1], o exemplo para o componente [Spinner],
- em [2], a caixa de diálogo exibida após clicar no botão [Submit].
Há aqui, para nós, três novidades:
- o componente [Spinner], que não existe por padrão no JSF,
- o mesmo vale para a caixa de diálogo,
- e, por fim, o POST, acionado pelo [Submit], é implementado com AJAX. Se observarmos atentamente o navegador durante a execução do POST, não vemos a ampulheta. A página não é recarregada. Ela é simplesmente modificada: um novo componente, neste caso a caixa de diálogo, aparece na página.
Vamos ver como tudo isso ocorre. O código XHTML do exemplo é o seguinte:
<h:form>
<p:panel header="Spinners">
<h:panelGrid id="grid" columns="2" cellpadding="5">
<h:outputLabel for="spinnerBasic" value="Basic Spinner: " />
<p:spinner id="spinnerBasic" value="#{spinnerController.number1}"/>
<h:outputLabel for="spinnerStep" value="Step Factor: " />
<p:spinner id="spinnerStep" value="#{spinnerController.number2}" stepFactor="0.25"/>
<h:outputLabel for="minmax" value="Min/Max: " />
<p:spinner id="minmax" value="#{spinnerController.number3}" min="0" max="100"/>
<h:outputLabel for="prefix" value="Prefix: " />
<p:spinner id="prefix" value="0" prefix="$" min="0" value="#{spinnerController.number4}"/>
<h:outputLabel for="ajaxspinner" value="Ajax Spinner: " />
<p:outputPanel>
<p:spinner id="ajaxspinner" value="#{spinnerController.number5}">
<p:ajax update="ajaxspinnervalue" process="@this" />
</p:spinner>
<h:outputText id="ajaxspinnervalue" value="#{spinnerController.number5}"/>
</p:outputPanel>
</h:panelGrid>
</p:panel>
<p:commandButton value="Submit" update="display" oncomplete="dialog.show()" />
<p:dialog header="Values" widgetVar="dialog" showEffect="fold" hideEffect="fold">
...
</p:dialog>
</h:form>
Em primeiro lugar, observemos que encontramos as tags clássicas do JSF: <h:form> na linha 1, <h:panelGrid> na linha 3, <h:outputLabel> na linha 4. Algumas tags JSF são reproduzidas por PF e aprimoradas: <p:commandButton> linha 21. Em seguida, encontramos tags PF de formatação: <p:panel> linha 2, <p:outputPanel> linha 13, <p:dialog> linha 23. Por fim, temos tags de entrada: <p:spinner> linha 5.
Vamos analisar esse código em relação à visualização:
![]() |
- em [1], o componente obtido com a tag <p:panel> da linha 2,
- em [2], o campo de entrada obtido pela combinação das tags <p:outputLabel> e <p:spinner>, linhas 6 e 7,
- em [3], o botão do POST obtido com a tag <p:commandButton> da linha 21,
- em [4], a caixa de diálogo das linhas 23 a 25,
- em [5], um contêiner invisível para dois componentes. Ele é criado pela tag <p:outputPanel> da linha 13.
Vamos analisar o código a seguir, que implementa uma ação AJAX:
<h:outputLabel for="ajaxspinner" value="Ajax Spinner: " />
<p:outputPanel>
<p:spinner id="ajaxspinner" value="#{spinnerController.number5}">
<p:ajax update="ajaxspinnervalue" process="@this" />
</p:spinner>
<h:outputText id="ajaxspinnervalue" value="#{spinnerController.number5}"/>
</p:outputPanel>
Esse código gera a seguinte visualização:
![]() |
- linha 1: exibe o texto [1]. É, ao mesmo tempo, um rótulo para o componente id=ajaxspinner (atributo for). Esse componente é o da linha 3 (atributo id),
- linhas 3-5: exibem o componente [2]. Esse componente é um componente de entrada/exibição associado ao modelo #{spinnerController.number5} (atributo “value”),
- linha 6: exibe o componente [3]. Este componente é um componente de exibição vinculado ao modelo #{spinnerController.number5} (atributo value),
- linha 4: a tag <p:ajax> adiciona um comportamento AJAX ao spinner. Sempre que este muda de valor, um POST com esse valor (atributo process="@this") é enviado ao modelo #{spinnerController.number5}. Feito isso, a página é atualizada (atributo update). Esse atributo tem como valor o id de um componente da página, neste caso, o da linha 6. O componente de destino do atributo update é então atualizado com o modelo. Este é novamente #{spinnerController.number5}, ou seja, o valor de spinner. Assim, o campo [3] acompanha as entradas do campo [2].
Trata-se aqui de um comportamento AJAX, sigla que significa Asynchronous JavaScript And XML. De maneira geral, um comportamento AJAX é o seguinte:
![]() |
- o navegador exibe uma página HTML que contém código JavaScript (J de AJAX). Os elementos da página formam um objeto JavaScript chamado DOM (Document Object Model),
- o servidor hospeda o aplicativo web que gerou essa página,
- em [1], ocorre um evento na página. Por exemplo, o incremento do spinner. Esse evento é gerenciado por JavaScript,
- No [2], o JavaScript gera um POST para o aplicativo web. Ele faz isso de forma assíncrona (o A de AJAX). O usuário pode continuar trabalhando com a página. Ela não fica congelada, mas é possível congelá-la, se necessário. O POST atualiza o modelo da página a partir dos valores enviados, neste caso o modelo #{spinnerController.number5},
- em [3]; a aplicação web retorna ao JavaScript uma resposta XML (o X de AJAX) ou JSON (JavaScript na notação de objeto),
- em [4], o JavaScript usa essa resposta para atualizar uma área específica do DOM, neste caso, a área de id=ajaxspinnervalue.
Ao utilizar o JSF e o Primefaces, o JavaScript é gerado pelo Primefaces. Essa biblioteca se baseia na biblioteca JavaScript JQuery. Da mesma forma, os componentes do Primefaces se baseiam nos da biblioteca de componentes JQuery e UI (Interface do Usuário). Portanto, o JQuery é a base do Primefaces.
Voltemos ao nosso exemplo e apresentemos agora o POST do botão [Submit]:
![]() |
O código associado ao POST é o seguinte:
<p:commandButton value="Submit" update="display" oncomplete="dialog.show()" />
<p:dialog header="Values" widgetVar="dialog" showEffect="fold" hideEffect="fold">
<h:panelGrid id="display" columns="2" cellpadding="5">
<h:outputText value="Value 1: " />
<h:outputText value="#{spinnerController.number1}" />
<h:outputText value="Value 2: " />
<h:outputText value="#{spinnerController.number2}" />
<h:outputText value="Value 3: " />
<h:outputText value="#{spinnerController.number3}" />
<h:outputText value="Value 4: " />
<h:outputText value="#{spinnerController.number4}" />
<h:outputText value="Value 5: " />
<h:outputText value="#{spinnerController.number5}" />
</h:panelGrid>
</p:dialog>
</h:form>
- linha 1: o POST é acionado pelo botão da linha 1. No Primefaces, as tags que acionam um POST fazem isso, por padrão, na forma de uma chamada AJAX. É por isso que essas tags possuem um atributo `update` para indicar o campo a ser atualizado, uma vez recebida a resposta do servidor. Aqui, o campo atualizado é o panelGrid da linha 4. Portanto, ao retornar o POST, esse campo será atualizado com os valores enviados ao modelo. No entanto, elas estão dentro de uma caixa de diálogo que não é visível por padrão. É o atributo oncomplete da linha 1 que a exibe. Esse evento ocorre ao final do processamento do POST. O valor desse atributo é um código JavaScript. Aqui, exibimos a caixa de diálogo com id=dialog, ou seja, a da linha 3 (atributo widgetVar),
- linha 3: vemos diversos atributos da caixa de diálogo. É preciso experimentar para ver o que eles fazem.
Já mencionamos o modelo, mas ainda não o apresentamos. É este aqui:
De maneira geral, pode-se proceder da seguinte forma:
- identificar o componente Primefaces que se deseja utilizar,
- analisar o exemplo correspondente. Os exemplos do Primefaces são bem elaborados e fáceis de entender.
5.4. Um primeiro projeto Primefaces: mv-pf-01
Vamos criar um projeto web Maven com o NetBeans:
![]() |
- [1, 2, 3]: criamos um projeto Maven do tipo [Web Application],
![]() |
- [4]: o servidor será o Tomcat,
- no [5], o projeto gerado,
- em [6], ele é limpo do arquivo [index.jsp] e do pacote Java,
![]() |
- em [7, 8]: nas propriedades do projeto, adiciona-se suporte para Java Server Faces,
![]() |
- para [9]; na aba [Components], seleciona-se a biblioteca de componentes PrimeFaces. O NetBeans oferece suporte a outras bibliotecas de componentes: ICEFaces e RichFaces.
- em [10], o projeto gerado. Em [11], observe-se a dependência do Primefaces.
Em resumo, um projeto Primefaces é um projeto JSF clássico ao qual foi adicionada uma dependência do Primefaces. Nada mais.
Tendo entendido isso, modificamos o arquivo [pom.xml] para trabalhar com as versões mais recentes das bibliotecas:
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.1.8</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>3.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>jsf20</id>
<name>Repository for library Library[jsf20]</name>
<url>http://download.java.net/maven/2/</url>
</repository>
<repository>
<id>primefaces</id>
<name>Repository for library Library[primefaces]</name>
<url>http://repository.primefaces.org/</url>
</repository>
</repositories>
Nas linhas 26 a 30, observe o repositório Maven para o Primefaces. Feitas essas alterações, compilamos o projeto para iniciar o download das dependências. Obtemos, então, o projeto [12].
Agora, vamos tentar reproduzir o exemplo que estudamos. A página [index.html] fica da seguinte forma:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>Spinner</title>
</h:head>
<h:body>
<!-- formulário -->
<h:form>
<p:panel header="Spinners">
<h:panelGrid id="grid" columns="2" cellpadding="5">
<h:outputLabel for="spinnerBasic" value="Basic Spinner: " />
<p:spinner id="spinnerBasic" value="#{spinnerController.number1}"/>
<h:outputLabel for="spinnerStep" value="Step Factor: " />
<p:spinner id="spinnerStep" value="#{spinnerController.number2}" stepFactor="0.25"/>
<h:outputLabel for="minmax" value="Min/Max: " />
<p:spinner id="minmax" value="#{spinnerController.number3}" min="0" max="100"/>
<h:outputLabel for="prefix" value="Prefix: " />
<p:spinner id="prefix" prefix="$" min="0" value="#{spinnerController.number4}"/>
<h:outputLabel for="ajaxspinner" value="Ajax Spinner: " />
<p:outputPanel>
<p:spinner id="ajaxspinner" value="#{spinnerController.number5}">
<p:ajax update="ajaxspinnervalue" process="@this" />
</p:spinner>
<h:outputText id="ajaxspinnervalue" value="#{spinnerController.number5}"/>
</p:outputPanel>
</h:panelGrid>
</p:panel>
<p:commandButton value="Submit" update="display" oncomplete="dialog.show()" />
<!-- caixa de diálogo -->
<p:dialog header="Values" widgetVar="dialog" showEffect="fold" hideEffect="fold">
<h:panelGrid id="display" columns="2" cellpadding="5">
<h:outputText value="Value 1: " />
<h:outputText value="#{spinnerController.number1}" />
<h:outputText value="Value 2: " />
<h:outputText value="#{spinnerController.number2}" />
<h:outputText value="Value 3: " />
<h:outputText value="#{spinnerController.number3}" />
<h:outputText value="Value 4: " />
<h:outputText value="#{spinnerController.number4}" />
<h:outputText value="Value 5: " />
<h:outputText value="#{spinnerController.number5}" />
</h:panelGrid>
</p:dialog>
</h:form>
</h:body>
</html>
Não podemos esquecer a linha 5, que declara o namespace da biblioteca de tags do Primefaces. Adicionamos ao projeto o bean que serve de modelo para a página:
![]() |
O bean é o seguinte:
package beans;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ManagedBean;
@ManagedBean
@RequestScoped
public class SpinnerController {
// modelo
private int number1;
private double number2;
private int number3;
private int number4;
private int number5;
// getters e setters
...
}
A classe é um bean (linha 6) com escopo de solicitação (linha 7). Como não foi especificado um nome, o bean recebe o nome da classe com a primeira letra em minúscula: spinnerController.
Ao executar o projeto, obtém-se o seguinte:
![]() |
Acabamos de mostrar como testar um exemplo retirado do site do Primefaces. Todos os exemplos podem ser testados dessa maneira.
A seguir, vamos nos concentrar apenas em alguns componentes do Primefaces. Primeiramente, retomaremos os exemplos estudados com JSF e substituiremos algumas tags JSF por tags do Primefaces. A aparência das páginas será ligeiramente alterada; elas terão um comportamento AJAX, mas os beans associados não precisarão ser alterados. Em cada um dos exemplos a seguir, nos limitaremos a apresentar o código XHTML das páginas e as capturas de tela correspondentes. O leitor é convidado a testar os exemplos para identificar as diferenças entre as páginas JSF e as páginas PF.
5.5. Exemplo mv-pf-02: gerenciador de eventos – internacionalização – navegação entre páginas
Este projeto é a adaptação do projeto JSF [mv-jsf2-02] (parágrafo 2.4, página 41):
![]() | ![]() |
O projeto NetBeans é o seguinte:
![]() |
A página [index.html] é a seguinte:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<f:view locale="#{changeLocale.locale}">
<h:head>
<title><h:outputText value="#{msg['welcome.titre']}" /></title>
</h:head>
<body>
<h:form id="formulaire">
<h:panelGrid columns="2">
<p:commandLink value="#{msg['welcome.langue1']}" action="#{changeLocale.setFrenchLocale}" ajax="false"/>
<p:commandLink value="#{msg['welcome.langue2']}" action="#{changeLocale.setEnglishLocale}" ajax="false"/>
</h:panelGrid>
<h1><h:outputText value="#{msg['welcome.titre']}" /></h1>
<p:commandLink value="#{msg['welcome.page1']}" action="page1" ajax="false"/>
</h:form>
</body>
</f:view>
</html>
Nas linhas 15, 16 e 19, as tags <h:commandLink> foram substituídas por tags <p:commandLink>. Essa tag tem um comportamento padrão AJAX, que pode ser desativado definindo o atributo ajax="false". Portanto, aqui, as tags <p:commandLink> se comportam como tags <h:commandLink>: a página será recarregada ao clicar nesses links.
5.6. Exemplo mv-pf-03: layout utilizando facelets
Este projeto apresenta a criação de páginas XHTML utilizando os modelos facelets do exemplo [mv-jsf2-09] (parágrafo 2.11):
![]() |
O projeto do NetBeans é o seguinte:
![]() |
- em [1], os arquivos de configuração do projeto JSF,
- em [2], as páginas XHTML,
- em [3], o bean de suporte para a mudança de idiomas,
- em [4], os arquivos de mensagens,
- em [5], as dependências.
As páginas do projeto têm como modelo a página [layout.xhtml]:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<f:view locale="#{changeLocale.locale}">
<h:head>
<title>JSF</title>
<h:outputStylesheet library="css" name="styles.css"/>
</h:head>
<h:body style="background-image: url('${request.contextPath}/resources/images/standard.jpg');">
<h:form id="formulaire">
<table style="width: 600px">
<tr>
<td colspan="2" bgcolor="#ccccff">
<ui:include src="entete.xhtml"/>
</td>
</tr>
<tr>
<td style="width: 100px; height: 200px" bgcolor="#ffcccc">
<ui:include src="menu.xhtml"/>
</td>
<td>
<p:outputPanel id="contenu">
<ui:insert name="contenu" >
<h2>Contenu</h2>
</ui:insert>
</p:outputPanel>
</td>
</tr>
<tr bgcolor="#ffcc66">
<td colspan="2">
<ui:include src="basdepage.xhtml"/>
</td>
</tr>
</table>
</h:form>
</h:body>
</f:view>
</html>
- linha 9: uma tag <f:view> envolve toda a página para aproveitar a internacionalização que ela permite,
- linha 15: um formulário com o ID “formulário”. Esse formulário constitui o corpo da página. Nesse corpo, há apenas uma parte dinâmica, a das linhas 28 a 30. É ali que será inserida a parte variável da página:
![]() |
- a área destacada acima será atualizada por chamadas AJAX. Para identificá-la, nós a incluímos em um contêiner Primefaces gerado pela tag <p:outputPanel> (linha 27). E esse contêiner foi nomeado “conteúdo” (atributo id). Como ele se encontra em um formulário que, por sua vez, é um contêiner chamado “formulário”, o nome completo da área dinâmica é:formulário:conteúdo. O primeiro “:” indica que partimos da raiz do documento, depois passamos pelo contêiner chamado “formulário” e, em seguida, pelo contêiner chamado “conteúdo”. Uma dificuldade com o AJAX é nomear corretamente as áreas a serem atualizadas por meio de uma chamada ao AJAX. O mais simples é examinar o código-fonte da página HTML recebida:
Acima, vemos que a tag <h:outputPanel> gerou uma tag HTML <span>. Neste exemplo, o nome relativo formulário:conteúdo (sem o : inicial) e o nome completo :formulário:conteúdo (com o : inicial) designam o mesmo objeto.
Vale lembrar que as chamadas AJAX (<p:commandButton>, <p:commandLink>) que atualizam a área dinâmica terão o atributo update=":formulário:conteúdo".
A página [index.xhtml] é a única página exibida pelo projeto:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition template="layout.xhtml">
<ui:define name="contenu">
<ui:fragment rendered="#{requestScope.page1 || requestScope.page2==null}">
<ui:include src="page1.xhtml"/>
</ui:fragment>
<ui:fragment rendered="#{requestScope.page2}">
<ui:include src="page2.xhtml"/>
</ui:fragment>
</ui:define>
</ui:composition>
</html>
- na linha 8, o modelo de [index.xhtml] é a página [layout.xhtml] que acabamos de apresentar,
- linha 9: é a área de ID de conteúdo que é atualizada por [index.html]. Nessa área, há dois fragmentos:
- o fragmento [page1.xhtml], linha 11;
- o fragmento [page2.xhtml], linha 14.
Esses dois fragmentos são mutuamente exclusivos.
- linha 10: o fragmento [page1.xhtml] é exibido se a consulta tiver o atributo page1 definido como true ou se o atributo page2 não existir. Esse é o caso da primeira consulta, na qual nenhum desses atributos estará presente na consulta. Nesse caso, será exibido o fragmento [page1.xhtml];
- linha 11; o fragmento [page2.xhtml] é exibido se a consulta tiver o atributo page2 definido como true
O fragmento [page1.xhtml] é o seguinte:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<body>
<h:panelGrid columns="2">
<p:commandLink value="#{msg['page1.langue1']}" actionListener="#{changeLocale.setFrenchLocale}" ajax="true" update=":formulaire:contenu"/>
<p:commandLink value="#{msg['page1.langue2']}" actionListener="#{changeLocale.setEnglishLocale}" ajax="true" update=":formulaire:contenu"/>
</h:panelGrid>
<h1><h:outputText value="#{msg['page1.titre']}" /></h1>
<p:commandLink value="#{msg['page1.lien']}" update=":formulaire:contenu">
<f:setPropertyActionListener value="#{true}" target="#{requestScope.page2}" />
</p:commandLink>
</body>
</html>
e exibe o seguinte conteúdo:
![]() |
- linhas 11 e 12, os dois links para alterar o idioma. Esses dois links geram chamadas AJAX (ajax=true). Essa é a configuração padrão. Portanto, não é necessário definir o atributo ajax=true. Não faremos mais isso daqui em diante. Observe que esses dois links atualizam a área :formulário:conteúdo (atributo update), que está destacada acima,
- linha 15: um link de navegação AJAX que, mais uma vez, atualiza a área :formulário:conteúdo,
- linha 16: utiliza-se a tag <h:setPropertyActionListener> para inserir o atributo page2 na consulta com o valor true. Isso fará com que o fragmento [page2.xhtml] (linha 6 abaixo) seja exibido na página [index.xhtml]:
<ui:composition template="layout.xhtml">
<ui:define name="contenu">
<ui:fragment rendered="#{requestScope.page1 || requestScope.page2==null}">
<ui:include src="page1.xhtml"/>
</ui:fragment>
<ui:fragment rendered="#{requestScope.page2}">
<ui:include src="page2.xhtml"/>
</ui:fragment>
</ui:define>
</ui:composition>
O fragmento [page2.xhtml] é semelhante:
![]() |
O código de [page2.xhtml] é o seguinte:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<body>
<h1><h:outputText value="#{msg['page2.entete']}"/></h1>
<p:commandLink value="#{msg['page2.lien']}" update=":formulaire:contenu">
<f:setPropertyActionListener value="#{true}" target="#{requestScope.page1}" />
</p:commandLink>
</body>
</html>
Deste exemplo, vamos reter os seguintes pontos para a continuação:
- utilizaremos o modelo [layout.xhtml] como modelo das páginas,
- a área dinâmica será identificada pelo id:formulário:conteúdo e será atualizada por chamadas ao AJAX.
5.7. Exemplo mv-pf-04: formulário de preenchimento
Este projeto é a adaptação do projeto JSF2 [mv-jsf2-03] (ver parágrafo 2.5):
![]() |
O projeto do NetBeans é o seguinte:
![]() |
Acima, em [1], estão as páginas XHTML do projeto. A formatação é feita pelo modelo [layout.xhtml], analisado anteriormente. A página [index.xhtml] é a única página do projeto. Ela é exibida na área :formulário:conteúdo. Seu código é o seguinte:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition template="layout.xhtml">
<ui:define name="contenu">
<ui:include src="page1.xhtml"/>
</ui:define>
</ui:composition>
</html>
Ela se limita a exibir o fragmento [page1.xhtml]. Este é equivalente ao formulário analisado no exemplo [mv-jsf2-03]. Vale lembrar que o objetivo daquele formulário era apresentar as tags de entrada JSF. Essas tags foram substituídas aqui por tags do Primefaces.
PanelGrid
Para formatar os elementos de [page1.xhtml], utilizamos a tag <p:panelGrid>. Por exemplo, para os dois links de idiomas:
<!-- idiomas -->
<p:panelGrid columns="2">
<p:commandLink value="#{msg['form.langue1']}" actionListener="#{changeLocale.setFrenchLocale}" update=":formulaire:contenu"/>
<p:commandLink value="#{msg['form.langue2']}" actionListener="#{changeLocale.setEnglishLocale}" update=":formulaire:contenu"/>
</p:panelGrid>
Isso resulta na seguinte exibição:
Outra forma da tag <p:panelGrid> é a seguinte:
<p:panelGrid>
<f:facet name="header">
<p:row>
<p:column colspan="3"><h:outputText value="#{msg['form.titre']}"/></p:column>
</p:row>
<p:row>
<p:column><h:outputText value="#{msg['form.headerCol1']}"/></p:column>
<p:column><h:outputText value="#{msg['form.headerCol2']}"/></p:column>
<p:column><h:outputText value="#{msg['form.headerCol3']}"/></p:column>
</p:row>
</f:facet>
<p:row>
<p:column>
<h:outputText value="inputText"/>
</p:column>
<p:column>
<h:outputLabel for="inputText" value="#{msg['form.loginPrompt']}" />
<p:inputText id="inputText" value="#{form.inputText}"/>
</p:column>
<p:column>
<h:outputText id="inputTextValue" value="#{form.inputText}"/>
</p:column>
</p:row>
...
<f:facet name="footer">
<p:row>
<p:column colspan="3">
<div align="center">
<p:commandButton value="#{msg['form.submitText']}" update=":formulaire:contenu"/>
</div>
</p:column>
</p:row>
</f:facet>
</p:panelGrid>
As linhas e colunas da tabela são identificadas pelas tags <p:row> e <p:column>.
As linhas 3 a 12 definem o cabeçalho da tabela:
As linhas 14 a 25 definem uma linha da tabela:
As linhas 27 a 35 definem o rodapé da tabela:
inputText
<p:row>
<p:column>
<h:outputText value="inputText"/>
</p:column>
<p:column>
<h:outputLabel for="inputText" value="#{msg['form.loginPrompt']}" />
<p:inputText id="inputText" value="#{form.inputText}"/>
</p:column>
<p:column>
<h:outputText id="inputTextValue" value="#{form.inputText}"/>
</p:column>
</p:row>
password
<p:row>
<p:column>
<h:outputText value="inputSecret"/>
</p:column>
<p:column>
<h:outputLabel for="inputSecret" value="#{msg['form.passwdPrompt']}"/>
<p:password id="inputSecret" value="#{form.inputSecret}" feedback="true"
promptLabel="#{msg['form.promptLabel']}" weakLabel="#{msg['form.weakLabel']}"
goodLabel="#{msg['form.goodLabel']}" strongLabel="#{msg['form.strongLabel']}" />
</p:column>
<p:column>
<h:outputText id="inputSecretValue" value="#{form.inputSecret}"/>
</p:column>
</p:row>
![]() |
Na linha 7, o atributo feedback=true permite obter um feedback sobre a qualidade da senha.
inputTextArea
<p:row>
<p:column>
<h:outputText value="inputTextArea"/>
</p:column>
<p:column>
<h:outputLabel for="inputTextArea" value="#{msg['form.descPrompt']}"/>
<p:editor id="inputTextArea" value="#{form.inputTextArea}" rows="4"/>
</p:column>
<p:column>
<h:outputText id="inputTextAreaValue" value="#{form.inputTextArea}"/>
</p:column>
</p:row>
![]() |
Na linha 7, a tag <p:editor> exibe um editor avançado que permite formatar o texto (fonte, tamanho, cor, alinhamento, etc.). O que é enviado ao servidor é o código HTML do texto digitado [2].
selectOneListBox
<p:row>
<p:column>
<h:outputText value="selectOneListBox"/>
</p:column>
<p:column>
<h:outputLabel for="selectOneListBox1" value="#{msg['form.selectOneListBox1Prompt']}"/>
<p:selectOneListbox id="selectOneListBox1" value="#{form.selectOneListBox1}">
<f:selectItem itemValue="1" itemLabel="un"/>
<f:selectItem itemValue="2" itemLabel="deux"/>
<f:selectItem itemValue="3" itemLabel="trois"/>
</p:selectOneListbox>
</p:column>
<p:column>
<h:outputText id="selectOneListBox1Value" value="#{form.selectOneListBox1}"/>
</p:column>
</p:row>
![]() |
selectOneMenu
<p:row>
<p:column>
<h:outputText value="selectOneMenu"/>
</p:column>
<p:column>
<h:outputLabel for="selectOneMenu" value="#{msg['form.selectOneMenuPrompt']}"/>
<p:selectOneMenu id="selectOneMenu" value="#{form.selectOneMenu}">
<f:selectItem itemValue="1" itemLabel="un"/>
<f:selectItem itemValue="2" itemLabel="deux"/>
<f:selectItem itemValue="3" itemLabel="trois"/>
<f:selectItem itemValue="4" itemLabel="quatre"/>
<f:selectItem itemValue="5" itemLabel="cinq"/>
</p:selectOneMenu>
</p:column>
<p:column>
<h:outputText id="selectOneMenuValue" value="#{form.selectOneMenu}"/>
</p:column>
</p:row>
![]() |
selectManyMenu
<p:row>
<p:column>
<h:outputText value="selectManyMenu"/>
</p:column>
<p:column>
<h:outputLabel for="selectManyMenu" value="#{msg['form.selectManyMenuPrompt']}"/>
<p:selectManyMenu id="selectManyMenu" value="#{form.selectManyMenu}" >
<f:selectItem itemValue="1" itemLabel="un"/>
<f:selectItem itemValue="2" itemLabel="deux"/>
<f:selectItem itemValue="3" itemLabel="trois"/>
<f:selectItem itemValue="4" itemLabel="quatre"/>
<f:selectItem itemValue="5" itemLabel="cinq"/>
</p:selectManyMenu>
<p:commandLink value="#{msg['form.buttonRazText']}" actionListener="#{form.clearSelectManyMenu()}" update=":formulaire:selectManyMenu" style="margin-left: 10px"/>
</p:column>
<p:column>
<h:outputText id="selectManyMenuValue" value="#{form.selectManyMenuValue}"/>
</p:column>
</p:row>
![]() |
Na linha 14, observe-se que o link [Raz] atualiza o campo :formulário:selectManyMenu com o valor AJAX, que corresponde ao componente da linha 6. No entanto, é importante saber que, durante o POST AJAX, todos os valores do formulário são enviados. Portanto, é todo o modelo que é atualizado. Com este modelo, no entanto, atualiza-se apenas o campo :formulário:selectManyMenu.
selectBooleanCheckbox
<p:row>
<p:column>
<h:outputText value="selectBooleanCheckbox"/>
</p:column>
<p:column>
<h:outputLabel for="selectBooleanCheckbox" value="#{msg['form.selectBooleanCheckboxPrompt']}"/>
<p:selectBooleanCheckbox id="selectBooleanCheckbox" value="#{form.selectBooleanCheckbox}"/>
</p:column>
<p:column>
<h:outputText id="selectBooleanCheckboxValue" value="#{form.selectBooleanCheckbox}"/>
</p:column>
</p:row>
selectManyCheckbox
<p:row>
<p:column>
<h:outputText value="selectManyCheckbox"/>
</p:column>
<p:column>
<h:outputLabel for="selectManyCheckbox" value="#{msg['form.selectManyCheckboxPrompt']}"/>
<p:selectManyCheckbox id="selectManyCheckbox" value="#{form.selectManyCheckbox}">
<f:selectItem itemValue="1" itemLabel="rouge"/>
<f:selectItem itemValue="2" itemLabel="bleu"/>
<f:selectItem itemValue="3" itemLabel="blanc"/>
<f:selectItem itemValue="4" itemLabel="noir"/>
</p:selectManyCheckbox>
</p:column>
<p:column>
<h:outputText id="selectManyCheckboxValue" value="#{form.selectManyCheckboxValue}"/>
</p:column>
</p:row>
selectOneRadio
<p:row>
<p:column>
<h:outputText value="selectOneRadio"/>
</p:column>
<p:column>
<h:outputLabel for="selectOneRadio" value="#{msg['form.selectOneRadioPrompt']}"/>
<p:selectOneRadio id="selectOneRadio" value="#{form.selectOneRadio}" >
<f:selectItem itemValue="1" itemLabel="voiture"/>
<f:selectItem itemValue="2" itemLabel="vélo"/>
<f:selectItem itemValue="3" itemLabel="scooter"/>
<f:selectItem itemValue="4" itemLabel="marche"/>
</p:selectOneRadio>
</p:column>
<p:column>
<h:outputText id="selectOneRadioValue" value="#{form.selectOneRadio}"/>
</p:column>
</p:row>
5.8. Exemplo: mv-pf-05: listas dinâmicas
Este projeto é a adaptação do projeto JSF2 [mv-jsf2-04] (ver parágrafo 2.6):

Este projeto não introduz novas tags do PrimeFaces em relação ao projeto anterior. Portanto, não o comentaremos. Ele faz parte da lista de exemplos disponibilizados ao leitor no site do documento.
5.9. Exemplo: mv-pf-06: navegação – sessão – gerenciamento de exceções
Este projeto é a adaptação do projeto JSF2 [mv-jsf2-05] (ver parágrafo 2.7):
![]() |
Mais uma vez, este exemplo não introduz novas tags do PrimeFaces. Comentaremos apenas a tabela de links destacada acima:
<p:panelGrid columns="6">
<p:commandLink value="1" action="form1?faces-redirect=true" ajax="false"/>
<p:commandLink value="2" action="#{form.doAction2}" ajax="false"/>
<p:commandLink value="3" action="form3?faces-redirect=true" ajax="false"/>
<p:commandLink value="4" action="#{form.doAction4}" ajax="false"/>
<p:commandLink value="#{msg['form.pagealeatoireLink']}" action="#{form.doAlea}" ajax="false"/>
<p:commandLink value="#{msg['form.exceptionLink']}" action="#{form.throwException}" ajax="false"/>
</p:panelGrid>
- todos os links possuem o atributo ajax=false. Portanto, ocorre um carregamento normal da página;
- observe-se nas linhas 2 e 4 como realizar um redirecionamento.
5.10. Exemplo: mv-pf-07: validação e conversão dos dados inseridos
Este projeto é a adaptação dos projetos JSF2 e [mv-jsf2-06] (ver parágrafo 2.8):

O aplicativo introduz duas novas tags, a tag <p:messages>:
<p:messages globalOnly="true"/>

e a tag <p:message>:
<p:inputText id="saisie1" value="#{form.saisie1}" styleClass="saisie"/>
<p:message for="saisie1" styleClass="error"/>
Em comparação com a tag <h:message> de JSF, a tag <p:message> de PF traz as seguintes alterações:
- a aparência da mensagem de erro é diferente em [1],
- o campo com entrada incorreta está destacado por uma moldura vermelha no [2].
5.11. Exemplo: mv-pf-08: eventos relacionados à mudança de estado de componentes
Este projeto é a adaptação do projeto JSF2 [mv-jsf2-07] (ver parágrafo 2.9):

O projeto JSF introduziu o conceito de listeners. O gerenciamento do listener com o Primefaces foi feito de maneira diferente.
Com o JSF:
Com o Primefaces:
- linha 2: a tag <h:selectOneMenu> sem o atributo valueChangeListener,
- linha 4: a tag <p:ajax> adiciona um comportamento AJAX à sua tag pai <h:selectOneMenu>. Por padrão, ela reage ao evento “mudança de valor” da lista combo1. Nesse evento, os valores do formulário ao qual ela pertence serão enviados ao servidor por meio de uma chamada AJAX. O modelo é, portanto, atualizado. Utiliza-se esse novo modelo para atualizar a lista suspensa identificada por combo2 (linha 10). Observe, na linha 4, que a chamada AJAX não executa nenhum método do modelo. Isso é desnecessário neste caso. Queremos simplesmente atualizar o modelo por meio da chamada POST com os valores inseridos.
5.12. Exemplo: mv-pf-09: preenchimento assistido
Este projeto apresenta campos de entrada específicos do Primefaces que facilitam a inserção de determinados tipos de dados:
![]() |
5.12.1. O projeto NetBeans
O projeto do NetBeans é o seguinte:
![]() |
O interesse do projeto reside em:
- na única página [index.html] exibida por ele,
- o modelo [Form.java] dessa página.
5.12.2. O modelo
O formulário apresenta quatro campos de preenchimento associados ao seguinte modelo:
package forms;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ManagedBean;
@ManagedBean
@SessionScoped
public class Form implements Serializable {
private Date calendrier;
private Integer slider = 100;
private Integer spinner = 1;
private String autocompleteValue;
public Form() {
}
public List<String> autocomplete(String query) {
...
}
// getters e setters
...
}
As quatro entradas estão associadas aos campos das linhas 14 a 17.
5.12.3. O formulário
O formulário é o seguinte:
<?xml version='1.0' encoding='UTF-8' ?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition template="layout.xhtml">
<ui:define name="contenu">
<h2><h:outputText value="#{msg['app.titre']}"/></h2>
<p:growl id="messages" autoUpdate="true"/>
<p:panelGrid columns="3" columnClasses="col1,col2,col3,col4">
<h:outputText value="#{msg['saisie.type']}" styleClass="entete"/>
<h:outputText value="#{msg['saisie.champ']}" styleClass="entete"/>
<h:outputText value="#{msg['bean.valeur']}" styleClass="entete"/>
<!-- calendário -->
...
<!-- controle deslizante -->
...
<!-- spinner -->
...
<!-- autocompletar -->
...
</p:panelGrid>
</ui:define>
</ui:composition>
</html>
Vamos examinar os quatro campos de preenchimento.
5.12.4. O calendário
A tag <p:calendar> permite selecionar uma data a partir de um calendário. Essa tag admite diversos atributos.
<h:outputText value="#{msg['calendar.prompt']}"/>
<p:calendar id="calendrier" value="#{form.calendrier}" pattern="dd/MM/yyyy" timeZone="Europe/Paris"/>
<h:outputText id="calendrierValue" value="#{form.calendrier}">
<f:convertDateTime pattern="dd/MM/yyyy" type="date" timeZone="Europe/Paris"/>
</h:outputText>
Na linha 2, indica-se que a data deve ser exibida no formato “dd/mm/aaaa” e que o fuso horário é o de Paris. Ao posicionar o cursor na área de preenchimento, um calendário é exibido:
![]() |
5.12.5. O controle deslizante
A tag <p:slider> permite inserir um número inteiro arrastando um cursor ao longo de uma barra:
O código da tag é o seguinte:
<h:outputText value="#{msg['slider.prompt']}"/>
<h:panelGrid columns="1" style="margin-bottom:10px">
<p:inputText id="slider" value="#{form.slider}" required="true" requiredMessage="#{msg['slider.required']}" validatorMessage="#{msg['slider.invalide']}">
<f:validateLongRange minimum="100" maximum="200"/>
</p:inputText>
<p:slider for="slider" minValue="100" maxValue="200"/>
</h:panelGrid>
<h:outputText id="sliderValue" value="#{form.slider}"/>
- linha 3: trata-se de uma tag <p:inputText> clássica que permite inserir o número inteiro. Esse número também pode ser inserido por meio do controle deslizante,
- linha 4: a tag <p:slider> está associada à tag de entrada <p:inputText> (atributo for). Definimos um valor mínimo e um valor máximo para ela.
5.12.6. O spinner
Já tivemos a oportunidade de apresentar esse componente:
<h:outputText value="#{msg['spinner.prompt']}"/>
<p:spinner id="spinner" min="1" max="12" value="#{form.spinner}" required="true" requiredMessage="#{msg['spinner.required']}" validatorMessage="#{msg['spinner.invalide']}">
<f:validateLongRange minimum="1" maximum="12"/>
</p:spinner>
<h:outputText id="spinnerValue" value="#{form.spinner}"/>
Linha 3: o spinner permite a inserção de um número inteiro entre 1 e 12. É possível digitar o número diretamente no campo de entrada do spinner ou usar as setas para aumentar ou diminuir o valor inserido.
5.12.7. Preenchimento assistido
A entrada assistida consiste em digitar os primeiros caracteres do que se deseja inserir. Sugestões aparecem então em uma lista suspensa. É possível selecionar uma delas. Esse componente é utilizado no lugar das listas suspensas quando estas têm um conteúdo muito extenso. Suponhamos que se queira apresentar uma lista suspensa das cidades da França. São vários milhares de cidades. Se permitirmos que o usuário digite os três primeiros caracteres do nome da cidade, poderemos então apresentar uma lista reduzida das cidades que começam com esses caracteres.
![]() |
O código desse componente é o seguinte:
<h:outputText value="#{msg['autocomplete.prompt']}"/>
<p:autoComplete value="#{form.autocompleteValue}" completeMethod="#{form.autocomplete}" required="true" requiredMessage="#{msg['autocomplete.required']}"/>
<h:outputText id="autocompleteValue" value="#{form.autocompleteValue}"/>
<h:panelGroup/>
<h:panelGroup>
<center><p:commandLink value="#{msg['valider']}" update="formulaire:contenu"/></center>
</h:panelGroup>
<h:panelGroup/>
A tag <p:autoComplete> na linha 2 é a que permite a entrada assistida. O parâmetro que nos interessa aqui é o atributo completeMethod, cujo valor é o nome de um método do modelo, responsável por fazer sugestões correspondentes aos caracteres digitados pelo usuário. Esse método é o seguinte:
public List<String> autocomplete(String query) {
List<String> results = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
results.add(query + i);
}
return results;
}
- linha 1: o método recebe como parâmetro a sequência de caracteres digitados pelo usuário na área de entrada. Ele retorna uma lista de sugestões,
- linhas 4-6: constrói-se uma lista de 10 sugestões que inclui os caracteres recebidos como parâmetros e adiciona a eles um algarismo de 0 a 9.
5.12.8. A tag <p:growl>
A tag <p:growl> é uma alternativa possível à tag <p:messages>, que exibe as mensagens de erro do formulário.
<p:growl id="messages" autoUpdate="true"/>
No exemplo acima, o atributo id não é utilizado. O atributo autoUpdate=true indica que a lista de mensagens de erro deve ser atualizada a cada envio do formulário.
Suponhamos que validemos o seguinte formulário [1]:
![]() |
- em [2], a tag <p:growl> exibe as mensagens de erro associadas aos dados inseridos incorretamente.
5.13. Exemplo: mv-pf-10: dataTable - 1
Este projeto apresenta a tag <p:dataTable>, que serve para exibir listas de dados

5.13.1. O projeto NetBeans
O projeto NetBeans é o seguinte:
![]() |
O interesse do projeto reside em:
- a única página [index.html] exibida por ele,
- no modelo [Form.java] dessa página e no bean [Personne].
5.13.2. O arquivo de mensagens
O arquivo [messages_fr.properties] é o seguinte:
app.titre=intro-08
app.titre2=DataTable - 1
submit=Valider
personnes.headers.id=Id
personnes.headers.nom=Nom
personnes.headers.prenom=Pr\u00e9nom
layout.hautdepage=Primefaces en fran\u00e7ais
layout.menu=Menu fran\u00e7ais
layout.basdepage=ISTIA, universit\u00e9 d'Angers
form.langue1=Fran\u00e7ais
form.langue2=Anglais
form.noData=La liste des personnes est vide
form.listePersonnes=Liste de personnes
form.action=Action
5.13.3. O modelo
O bean [Personne] representa uma pessoa:
package forms;
import java.io.Serializable;
public class Personne implements Serializable{
// dados
private int id;
private String nom;
private String prénom;
// fabricantes
public Personne(){
}
public Personne(int id, String nom, String prénom){
this.id=id;
this.nom=nom;
this.prénom=prénom;
}
// toString
public String toString(){
return String.format("Personne[%d,%s,%s]", id,nom,prénom);
}
// getters e setters
...
}
O modelo da página [index.xhtml] é a seguinte classe [Form]:
package forms;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean
@SessionScoped
public class Form implements Serializable{
// modelo
private List<Personne> personnes;
private int personneId;
// construtor
public Form() {
// inicialização da lista de pessoas
personnes = new ArrayList<Personne>();
personnes.add(new Personne(1, "dupont", "jacques"));
personnes.add(new Personne(2, "durand", "élise"));
personnes.add(new Personne(3, "martin", "jacqueline"));
}
public void retirerPersonne() {
...
}
// getters e setters
...
}
- linhas 9-10: o bean tem escopo de sessão,
- linhas 18-24: o construtor cria uma lista de três pessoas, lista essa que permanecerá ativa ao longo das solicitações,
- linha 15: o número de uma pessoa a ser removida da lista,
- linhas 26-28: o método de exclusão.
5.13.4. O formulário
O formulário é o seguinte: [index.xhtml]:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition template="layout.xhtml">
<ui:define name="contenu">
<h2><h:outputText value="#{msg['app.titre2']}"/></h2>
<p:dataTable value="#{form.personnes}" var="personne" emptyMessage="#{msg['form.noData']}">
<f:facet name="header">
#{msg['form.listePersonnes']}
</f:facet>
<p:column>
<f:facet name="header">
#{msg['personnes.headers.id']}
</f:facet>
#{personne.id}
</p:column>
<p:column>
<f:facet name="header">
#{msg['personnes.headers.nom']}
</f:facet>
#{personne.nom}
</p:column>
<p:column>
<f:facet name="header">
#{msg['personnes.headers.prenom']}
</f:facet>
#{personne.prénom}
</p:column>
<p:column>
<f:facet name="header">
#{msg['form.action']}
</f:facet>
<p:commandLink value="Retirer" action="#{form.retirerPersonne}" update=":formulaire:contenu">
<f:setPropertyActionListener target="#{form.personneId}" value="#{personne.id}"/>
</p:commandLink>
</p:column>
</p:dataTable>
</ui:define>
</ui:composition>
</html>
Isso gera a seguinte visualização (quadro abaixo):
![]() |
- linha 12: gera a tabela destacada acima. O atributo value indica a coleção exibida pela tabela, neste caso, a lista de pessoas do modelo. O atributo emptyMessage é opcional. Ele indica a mensagem a ser exibida quando a lista estiver vazia. Por padrão, é “no records found”. Aqui, será:
![]() |
- linhas 13-15: geram o cabeçalho [1],
- linhas 16-21: geram a coluna [2],
- linhas 22-27: geram a coluna [3],
- linhas 28-33: geram a coluna [4],
- linhas 34-41: geram a coluna [5].
O link [Retirer] permite remover uma pessoa da lista. Na linha [38], é o método [Form].retirerPersonne que realiza essa tarefa. Ele precisa saber o número da pessoa a ser removida. Esse número é fornecido na linha 39. Na linha 38, utilizou-se o atributo “action”. Em outras ocasiões, utilizou-se o atributo actionListener. Não tenho certeza se compreendi bem a diferença funcional entre esses dois atributos. Na prática, percebe-se, no entanto, que os atributos definidos pelas tags <setPropertyActionListener> são definidos antes da execução do método designado pelo atributo “action”, e que isso não ocorre com o atributo actionListener. Em resumo, sempre que houver parâmetros a serem enviados para a ação chamada, é necessário usar o atributo action.
O método para remover uma pessoa é o seguinte:
...
@ManagedBean
@SessionScoped
public class Form implements Serializable{
// modelo
private List<Personne> personnes;
private int personneId;
public void retirerPersonne() {
// procurando a pessoa selecionada
int i = 0;
for (Personne personne : personnes) {
// pessoa atual = pessoa selecionada?
if (personne.getId() == personneId) {
// a pessoa atual é removida da lista
personnes.remove(i);
// concluído
break;
} else {
// próxima pessoa
i++;
}
}
}
...
}
5.14. Exemplo: mv-pf-11: dataTable - 2
Este projeto apresenta uma tabela que exibe uma lista de dados, na qual uma linha pode ser selecionada:
![]() |
Ao selecionar uma linha da tabela, no momento do POST, são enviadas informações ao modelo sobre a linha selecionada. Assim, não é mais necessário um link [Retirer] por pessoa. Basta um único link para toda a tabela.
O projeto NetBeans é idêntico ao anterior, com algumas pequenas diferenças: o formulário e seu modelo. O formulário [index.xhtml] é o seguinte:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition template="layout.xhtml">
<ui:define name="contenu">
<h2><h:outputText value="#{msg['app.titre2']}"/></h2>
<p:dataTable value="#{form.personnes}" var="personne" emptyMessage="#{msg['form.noData']}"
rowKey="#{personne.id}" selection="#{form.personneChoisie}" selectionMode="single">
...
</p:dataTable>
<p:commandLink value="Retirer" action="#{form.retirerPersonne}" update=":formulaire:contenu"/>
</ui:define>
</ui:composition>
</html>
- linha 13: o atributo selectionMode permite escolher um modo de seleção single ou multiple. Aqui, optamos por selecionar apenas uma linha,
- linha 13: o atributo rowkey designa um atributo dos elementos exibidos que permite selecioná-los de forma exclusiva. Aqui, escolhemos o id da pessoa selecionada,
- linha 13: o atributo `selection` indica o atributo do modelo que receberá uma referência da pessoa selecionada. Graças ao atributo `rowkey` anterior, no lado do servidor será possível calcular uma referência da pessoa selecionada. Não temos os detalhes do método utilizado. Podemos imaginar que a coleção seja percorrida sequencialmente em busca do elemento correspondente ao rowkey selecionado. Isso significa que, se o método que associa rowkey a selection for mais complexo, então esse método não é utilizável,
Dito isso, o método [Form].retirerPersonne sofre as seguintes alterações:
...
@ManagedBean
@SessionScoped
public class Form implements Serializable {
// modelo
private List<Personne> personnes;
private Personne personneChoisie;
// fabricante
public Form() {
...
}
public void retirerPersonne() {
// remover a pessoa selecionada
personnes.remove(personneChoisie);
}
// getters e setters
...
}
- linha 9: a cada POST, a referência da linha 9 é inicializada com a referência, na lista da linha 8, da pessoa selecionada,
- em 18: a exclusão da pessoa fica, assim, simplificada. A pesquisa que realizamos no exemplo anterior foi feita por meio da tag <dataTable>.
5.15. Exemplo: mv-pf-12: dataTable - 3
Este projeto é semelhante ao anterior. A visualização, em particular, é idêntica:

O projeto do NetBeans é idêntico ao anterior, com algumas pequenas diferenças que vamos examinar. O formulário [index.xhtml] é alterado da seguinte forma:
...
<ui:composition template="layout.xhtml">
<ui:define name="contenu">
<h2><h:outputText value="#{msg['app.titre2']}"/></h2>
<p:dataTable value="#{form.personnes}" var="personne" emptyMessage="#{msg['form.noData']}"
selectionMode="single" selection="#{form.personneChoisie}">
...
</p:dataTable>
<p:commandLink value="Retirer" action="#{form.retirerPersonne}" update=":formulaire:contenu"/>
</ui:define>
</ui:composition>
</html>
- Na linha 6, o atributo rowkey foi removido, mas o atributo selection permanece. A ligação entre os atributos rowkey e selection agora é feita por meio de uma classe. O atributo value da linha 5 agora tem como valor uma instância da interface Primefaces SelectableDataModel<T>. O método [Form].getPersonnes do modelo sofreu as seguintes alterações:
public DataTableModel getPersonnes() {
return new DataTableModel(personnes);
}
Assim, um novo bean é adicionado ao projeto:
![]() |
Esse bean é o seguinte:
package forms;
import java.util.List;
import javax.faces.model.ListDataModel;
import org.primefaces.model.SelectableDataModel;
public class DataTableModel extends ListDataModel<Personne> implements SelectableDataModel<Personne> {
// construtores
public DataTableModel() {
}
public DataTableModel(List<Personne> personnes) {
super(personnes);
}
@Override
public Object getRowKey(Personne personne) {
return personne.getId();
}
@Override
public Personne getRowData(String rowKey) {
// lista de pessoas
List<Personne> personnes = (List<Personne>) getWrappedData();
// a chave é um número inteiro
int key = Integer.parseInt(rowKey);
// procura-se a pessoa selecionada
for (Personne personne : personnes) {
if (personne.getId() == key) {
return personne;
}
}
// não foi encontrado nada
return null;
}
}
- linha 7: a classe é uma instância da interface SelectableDataModel. Pelo menos duas classes implementam essa interface: ListDataModel, cujo construtor aceita uma lista como parâmetro, e ArrayDataModel, cujo construtor aceita um array como parâmetro. Aqui, nosso bean estende a classe ListDataModel,
- linhas 13-15: o construtor aceita como parâmetro a lista de pessoas que gerenciamos. Esse parâmetro é passado para a classe pai,
- linha 18: o método getRowKey desempenha a função do atributo rowkey, que foi removido. Ele deve retornar o objeto que permite identificar uma pessoa de forma única, neste caso, o ID da pessoa,
- linha 23: o método getRowData deve retornar o objeto selecionado, a partir de seu rowkey. Portanto, neste caso, retornar uma pessoa a partir de seu ID. A referência assim obtida será atribuída ao objeto de destino do atributo selection na tag dataTable, neste caso o atributo selection="#{form.personneChoisie}". O parâmetro do método é o rowkey do objeto selecionado pelo usuário, na forma de uma sequência de caracteres,
- linhas 24-35: fornecem a referência da pessoa cujo id foi recebido. Essa referência será atribuída ao modelo [Form].personneChoisie. O método [retirerPersonne] permanece, portanto, inalterado:
public void retirerPersonne() {
// a pessoa escolhida é removida
personnes.remove(personneChoisie);
}
Essa é a técnica a ser utilizada quando a ligação entre os atributos rowkey e selection não é uma simples ligação de propriedade (rowkey**) a objeto (selection**).
5.16. Exemplo: mv-pf-13: dataTable - 4
Este projeto é semelhante ao anterior, exceto que o modo de seleção da pessoa a ser removida muda:

Acima, vemos que o objeto é selecionado por meio de um menu de contexto (clique com o botão direito). É solicitada uma confirmação da exclusão:
![]() |
O formulário [index.xhtml] é alterado da seguinte forma:
...
<ui:composition template="layout.xhtml">
<ui:define name="contenu">
<!-- título -->
<h2><h:outputText value="#{msg['app.titre2']}"/></h2>
<!-- menu de contexto -->
<p:contextMenu for="personnes">
<p:menuitem value="#{msg['form.supprimer']}" onclick="confirmation.show()"/>
</p:contextMenu>
<!-- caixa de diálogo -->
<p:confirmDialog widgetVar="confirmation" message="#{msg['form.suppression.confirmation']}"
header="#{msg['form.suppression.message']}" severity="alert" >
<p:commandButton value="#{msg['form.supprimer.oui']}" update=":formulaire:contenu" action="#{form.retirerPersonne}" oncomplete="confirmation.hide()"/>
<p:commandButton value="#{msg['form.supprimer.non']}" onclick="confirmation.hide()" type="button" />
</p:confirmDialog>
<!-- dataTable-->
<p:dataTable id="personnes" value="#{form.personnes}" var="personne" emptyMessage="#{msg['form.noData']}"
selection="#{form.personneChoisie}" selectionMode="single">
...
</p:dataTable>
</ui:define>
</ui:composition>
</html>
- linhas 9-11: definem um menu de contexto para (atributo for) o dataTable da linha 21 (atributo id). Portanto, esse menu de contexto aparece ao clicar com o botão direito do mouse na tabela de pessoas,
- linha 10: nosso menu possui apenas uma opção (tag menuItem). Quando essa opção é clicada, o código JavaScript do atributo onclick é executado. O código JavaScript [confirmation.show()] exibe a caixa de diálogo da linha 14 (atributo widgetVar). Ela é a seguinte:
![]() |
- linha 14: o atributo message exibe [3], o atributo header exibe [1], o atributo severity exibe o ícone [2],
- linha 16: exibe [4]. Ao clicar, a pessoa é excluída (atributo action) e, em seguida, a caixa de diálogo é fechada (atributo oncomplete). O atributo oncomplete é um código JavaScript que é executado assim que a ação do lado do servidor for concluída,
- linha 17: exibe [5]. Ao clicar, a caixa de diálogo é fechada e a pessoa não é excluída.
5.17. Exemplo: mv-pf-14: dataTable - 5
Este projeto mostra que é possível obter uma resposta do servidor após a execução de uma chamada AJAX. Para isso, utiliza-se o atributo oncomplete da chamada AJAX:
![]() |
O formulário [index.xhtml] é alterado da seguinte forma:
...
<ui:composition template="layout.xhtml">
<ui:define name="contenu">
...
<!-- caixa de diálogo 1 -->
<p:confirmDialog widgetVar="confirmation" ... >
<p:commandButton value="#{msg['form.supprimer.oui']}" update=":formulaire:contenu" action="#{form.retirerPersonne}" oncomplete="handleRequest(xhr, status, args);confirmation.hide()"/>
<p:commandButton ... />
</p:confirmDialog>
<!-- JavaScript -->
<script type="text/javascript">
function handleRequest(xhr, status, args) {
// erro?
if(args.msgErreur) {
alert(args.msgErreur);
}
}
</script>
...
</p:dataTable>
</ui:define>
</ui:composition>
</html>
- linha 7: o atributo oncomplete chama a função JavaScript das linhas 13 a 18,
- linha 13: a assinatura do método deve ser esta. args é um dicionário que o modelo do lado do servidor pode enriquecer,
- linha 15: verifica-se se o dicionário `args` possui um atributo chamado 'msgErreur'. Se sim, ele é exibido (linha 16).
No modelo, o método [retirerPersonne] é implementado da seguinte forma:
public void retirerPersonne() {
// exclusão aleatória
int i = (int) (Math.random() * 2);
if (i == 0) {
// a pessoa selecionada é removida
personnes.remove(personneChoisie);
} else {
// retorna um erro
String msgErreur = Messages.getMessage(null, "form.msgErreur", null).getSummary();
RequestContext.getCurrentInstance().addCallbackParam("msgErreur", msgErreur);
}
}
- linha 3: gera-se um número aleatório 0 ou 1,
- linhas 4-6: se for 0, a pessoa selecionada pelo usuário é removida da lista de pessoas,
- linha 9: caso contrário, é gerada uma mensagem de erro internacionalizada:
form.msgErreur=La personne n'a pu \u00eatre supprim\u00e9e. Veuillez r\u00e9essayer ult\u00e9rieurement.
form.msgErreur_detail=La personne n'a pu \u00eatre supprim\u00e9e. Veuillez r\u00e9essayer ult\u00e9rieurement.
- linha 10: uma instrução complexa que tem como objetivo adicionar ao dicionário args, do qual já falamos, o atributo chamado 'msgErreur' com o valor msgErreur gerado na linha 9. Esse atributo é recuperado em seguida pelo método JavaScript de [index.xhtml]:
<!-- JavaScript -->
<script type="text/javascript">
function handleRequest(xhr, status, args) {
// erro?
if(args.msgErreur) {
alert(args.msgErreur);
}
}
</script>
5.18. Exemplo: mv-pf-15: a barra de ferramentas
Neste projeto, estamos criando uma barra de ferramentas:
![]() |
A barra de ferramentas é o componente destacado acima. Ela é obtida com o código XHTML a seguir, [index.xhtml]:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition template="layout.xhtml">
<ui:define name="contenu">
<!-- título -->
<h2><h:outputText value="#{msg['app.titre2']}"/></h2>
<!-- barra de ferramentas-->
<p:toolbar>
<p:toolbarGroup align="left">
...
</p:toolbarGroup>
<p:toolbarGroup align="right">
...
</p:toolbarGroup>
</p:toolbar>
</ui:define>
</ui:composition>
</html>
- linhas 15-22: a barra de ferramentas,
- linhas 16-18: definem o grupo de componentes à esquerda da barra,
- linhas 19-21: o mesmo para os componentes à direita.
Os componentes à esquerda da barra de ferramentas são os seguintes:
<p:toolbarGroup align="left">
<h:outputText value="#{msg['form.etudiant']}"/>
<p:spacer width="50px"/>
<p:selectOneMenu value="#{form.personneId}" effect="fade">
<f:selectItems value="#{form.personnes}" var="personne" itemLabel="#{personne.prénom} #{personne.nom}" itemValue="#{personne.id}"/>
</p:selectOneMenu>
<p:separator/>
<p:commandButton id="delete-personne" icon="ui-icon-trash" action="#{form.supprimerPersonne}" update=":formulaire:contenu"/>
<p:tooltip for="delete-personne" value="#{msg['form.delete.personne']}"/>
</p:toolbarGroup>
Eles exibem a visualização abaixo:
![]() |
- linha 2: exibe [1],
- linha 3: exibe um espaço de 30 pixels [2],
- linhas 4-6: exibem uma lista suspensa com uma lista de pessoas [3],
- linha 7: exibe um separador [4],
- linha 8: exibe um botão [5] responsável por excluir a pessoa selecionada na lista suspensa. O botão possui um ícone. Esses ícones são os de JQuery e UI. A lista deles pode ser encontrada em URL, [http://jqueryui.com/themeroller/] e [6]:
![]() |
- Para saber o nome de um ícone, basta passar o mouse sobre ele. Em seguida, esse nome é usado no atributo icon do componente <commandButton>, por exemplo, icon="ui-icon-trash". Observe que, no exemplo acima, o nome atribuído será .ui-icon-trash e que o ponto inicial desse nome é removido no atributo icon,
- linha 9: cria uma bolha de ajuda para o botão (atributo for). Ao passar o cursor sobre o botão, a mensagem de ajuda é exibida: [7].
O modelo associado a esses componentes é o seguinte:
package forms;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean
@SessionScoped
public class Form implements Serializable {
// modelo
private List<Personne> personnes;
private int personneId;
// fabricante
public Form() {
// inicialização da lista de pessoas
personnes = new ArrayList<Personne>();
personnes.add(new Personne(1, "dupont", "jacques"));
personnes.add(new Personne(2, "durand", "élise"));
personnes.add(new Personne(3, "martin", "jacqueline"));
}
public void supprimerPersonne() {
// procurando a pessoa selecionada
int i = 0;
for (Personne personne : personnes) {
// pessoa atual = pessoa selecionada?
if (personne.getId() == personneId) {
// excluindo a pessoa atual da lista
personnes.remove(i);
// concluído
break;
} else {
// próxima pessoa
i++;
}
}
}
// getters e setters
...
}
Os componentes à direita da barra de ferramentas são os seguintes:
<p:toolbar>
<p:toolbarGroup align="left">
...
</p:toolbarGroup>
<p:toolbarGroup align="right">
<p:menuButton value="#{msg['form.options']}">
<p:menuitem id="menuitem-francais" value="#{msg['form.francais']}" actionListener="#{changeLocale.setFrenchLocale}" update=":formulaire"/>
<p:menuitem id="menuitem-anglais" value="#{msg['form.anglais']}" actionListener="#{changeLocale.setEnglishLocale}" update=":formulaire"/>
</p:menuButton>
</p:toolbarGroup>
</p:toolbar>
Eles exibem a visualização abaixo:
![]() |
- linhas 6-9: um botão de menu. Ele contém opções de menu,
- linha 7: a opção para mudar o formulário para o francês,
- linha 8: a opção para alterá-lo para o inglês.
5.19. Conclusion
Já sabemos o suficiente para portar nosso aplicativo de exemplo para o Primefaces. Vimos apenas cerca de quinze componentes, embora a biblioteca possua mais de 100. O leitor é convidado a procurar o componente que lhe faltar diretamente no site do Primefaces.
5.20. Testes com o Eclipse
Os projetos Maven estão disponíveis no site de exemplos [1]:
![]() |
Depois de importados para o Eclipse, é possível executá-los [2]. Selecione o Tomcat em [3]. Eles serão exibidos no navegador interno do Eclipse [3].
![]() |



















































