5. Introdução à biblioteca de componentes PrimeFaces
5.1. O papel do PrimeFaces numa aplicação JSF
Voltemos à arquitetura de uma aplicação JSF, tal como a estudámos no início deste documento:
![]() |
As páginas JSF foram criadas utilizando três bibliotecas de tags:
- linha 2: as tags <h:x> do namespace [http://java.sun.com/jsf/html], que correspondem a tags HTML,
- linha 3: as tags <f:y> no namespace [http://java.sun.com/jsf/core] que correspondem a tags JSF,
- linha 4: as tags <ui:z> do namespace [http://java.sun.com/jsf/facelets], que correspondem às tags facelet.
Para criar 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.
Esta é a única alteração que será feita. Por isso, aparece nas visualizações. Os manipuladores de eventos e os modelos permanecem os mesmos que eram com o JSF. Este é um ponto importante a compreender.
A utilização de componentes PrimeFaces permite criar interfaces web mais intuitivas, graças aos muitos componentes desta biblioteca, e mais fluidas, graças à tecnologia AJAX que suporta nativamente. Estas são designadas por interfaces ricas ou RIAs (Rich Internet Applications).
A arquitetura JSF anterior passará a ser a seguinte arquitetura PF (PrimeFaces):
![]() |
5.2. As vantagens do PrimeFaces
O site do PrimeFaces [http://www.primefaces.org/showcase/ui/home.jsf] fornece uma lista de componentes que podem ser utilizados numa página PF:
![]() |
Nos exemplos a seguir, utilizaremos as duas primeiras funcionalidades do PrimeFaces:
- alguns dos cerca de cem componentes oferecidos,
- o seu comportamento AJAX nativo.
Entre os componentes disponíveis:
![]() | ![]() | ![]() |
Iremos utilizar apenas cerca de quinze deles nos nossos exemplos, mas isso será suficiente para compreender os princípios da construção de uma página PrimeFaces.
5.3. Aprendendo o PrimeFaces
O PrimeFaces fornece exemplos de utilização para cada um dos seus componentes. Basta clicar na ligação. 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].
Existem aqui três novas funcionalidades para nós:
- o componente [Spinner], que não existe por predefinição no JSF,
- o mesmo se aplica à caixa de diálogo,
- e, finalmente, o POST acionado pelo botão [Submit] é tratado via AJAX. Se observar atentamente o navegador durante o POST, não verá a ampulheta. A página não é recarregada. É simplesmente modificada: um novo componente — neste caso, a caixa de diálogo — aparece na página.
Vamos ver como tudo isto funciona. O código XHTML para o 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>
Primeiro, repare que vemos tags JSF padrão: <h:form> na linha 1, <h:panelGrid> na linha 3, <h:outputLabel> na linha 4. Algumas tags JSF são reutilizadas pelo PF e melhoradas: <p:commandButton> na linha 21. Em seguida, encontramos as tags de formatação do PF: <p:panel> na linha 2, <p:outputPanel> na linha 13, <p:dialog> na linha 23. Por fim, temos as tags de entrada: <p:spinner> na linha 5.
Vamos analisar este código em relação à vista:
![]() |
- em [1], o componente criado com a tag <p:panel> na linha 2,
- em [2], o campo de entrada criado pela combinação das tags <p:outputLabel> e <p:spinner> nas linhas 6 e 7,
- em [3], o botão POST criado com a tag <p:commandButton> na linha 21,
- em [4], a caixa de diálogo das linhas 23–25,
- em [5], um contentor invisível para dois componentes. É criado pela tag <p:outputPanel> na linha 13.
Vamos analisar o código seguinte 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>
Este código gera a seguinte visualização:
![]() |
- linha 1: exibe o texto [1]. Também serve como rótulo para o componente com id=ajaxspinner (atributo). Este componente é o da linha 3 (atributo id),
- Linhas 3–5: exibem o componente [2]. Este 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 ligado ao modelo #{spinnerController.number5} (atributo value),
- linha 4: a tag <p:ajax> adiciona comportamento AJAX ao spinner. Sempre que o spinner altera o seu valor, é enviada uma solicitação POST contendo esse valor (atributo process="@this") para o modelo #{spinnerController.number5}. Assim que isto é feito, a página é atualizada (atributo update). O valor deste atributo é o ID de um componente na página, neste caso o da linha 6. O componente a que o atributo update se refere é então atualizado com o modelo. Este é novamente #{spinnerController.number5}, ou seja, o valor do spinner. Assim, o campo [3] segue as entradas do campo [2].
Trata-se de um comportamento AJAX, um acrónimo que significa Asynchronous JavaScript and XML. De um modo geral, um comportamento AJAX funciona da seguinte forma:
![]() |
- o navegador apresenta uma página HTML que contém código JavaScript (o «J» em AJAX). Os elementos da página formam um objeto JavaScript chamado DOM (Document Object Model),
- o servidor hospeda a aplicação web que gerou esta página,
- em [1], ocorre um evento na página. Por exemplo, o indicador de carregamento avança. Este evento é tratado pelo JavaScript,
- em [2], o JavaScript envia um pedido POST para a aplicação web. Faz-o de forma assíncrona (o A em AJAX). O utilizador pode continuar a trabalhar com a página. Esta não fica congelada, mas pode ser congelada se necessário. O POST atualiza o modelo da página com base nos valores enviados, neste caso o modelo #{spinnerController.number5},
- em [3], a aplicação web envia uma resposta XML (o X em AJAX) ou JSON (JavaScript Object Notation) de volta para o JavaScript,
- em [4], o JavaScript utiliza esta resposta para atualizar uma área específica do DOM, neste caso a área com id=ajaxspinnervalue.
Ao utilizar JSF e PrimeFaces, o JavaScript é gerado pelo PrimeFaces. Esta biblioteca depende da biblioteca JavaScript jQuery. Da mesma forma, os componentes do PrimeFaces dependem dos componentes da biblioteca jQuery UI (User Interface). Portanto, o jQuery constitui a base do PrimeFaces.
Voltemos ao nosso exemplo e analisemos agora o pedido 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 pedido POST é acionado pelo botão na linha 1. No PrimeFaces, as tags que acionam um pedido POST fazem-no, por predefinição, através de uma chamada AJAX. É por isso que estas tags possuem um atributo `update` para especificar a área a ser atualizada assim que a resposta do servidor for recebida. Aqui, a área a ser atualizada é o `panelGrid` na linha 4. Assim, quando a resposta POST for recebida, esta área será atualizada com os valores enviados para o modelo. No entanto, estes valores estão contidos numa caixa de diálogo que está oculta por predefinição. É o atributo oncomplete na linha 1 que a exibe. Este evento ocorre no final do processamento POST. O valor deste atributo é código JavaScript. Aqui, exibimos a caixa de diálogo com id=dialog, que é a da linha 3 (atributo widgetVar),
- Linha 3: Vemos vários atributos da caixa de diálogo. Terá de experimentar para ver o que fazem.
Já mencionámos o modelo, mas ainda não o mostrámos. Aqui está ele:
De um modo geral, pode proceder da seguinte forma:
- identifique o componente PrimeFaces que pretende utilizar,
- estude o seu exemplo. Os exemplos do PrimeFaces são bem escritos e fáceis de compreender.
5.4. Um primeiro projeto PrimeFaces: mv-pf-01
Vamos criar um projeto web Maven com o NetBeans:
![]() |
- [1, 2, 3]: criar um projeto Maven do tipo [Aplicação Web],
![]() |
- [4]: o servidor será o Tomcat,
- em [5], o projeto gerado,
- em [6], remova o ficheiro [index.jsp] e o pacote Java,
![]() |
- em [7, 8]: nas propriedades do projeto, adicionamos suporte para Java Server Faces,
![]() |
- em [9], no separador [Componentes], selecione a biblioteca de componentes PrimeFaces. O NetBeans oferece suporte para outras bibliotecas de componentes: ICEFaces e RichFaces.
- Em [10], o projeto gerado. Em [11], repare na dependência do PrimeFaces.
Em resumo, um projeto PrimeFaces é um projeto JSF padrão ao qual foi adicionada uma dependência do PrimeFaces. Nada mais.
Agora que compreendemos isto, modificamos o ficheiro [pom.xml] para funcionar 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>
Linhas 26–30: Repare no repositório Maven para o PrimeFaces. Depois de efetuar estas alterações, compile o projeto para iniciar o download das dependências. Obterá então o projeto [12].
Agora, vamos tentar reproduzir o exemplo que estudámos. 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>
<!-- form -->
<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()" />
<!-- dialog box -->
<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 se esqueça da linha 5, que declara o namespace para a biblioteca de tags PrimeFaces. Adicione ao projeto o bean que serve de modelo para a página:
![]() |
O código é o seguinte:
package beans;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ManagedBean;
@ManagedBean
@RequestScoped
public class SpinnerController {
// model
private int number1;
private double number2;
private int number3;
private int number4;
private int number5;
// getters and setters
...
}
A classe é um bean (linha 6) com âmbito de solicitação (linha 7). Como não foi especificado nenhum nome, o bean recebe o nome da classe com a primeira letra minúscula: spinnerController.
Quando executamos o projeto, obtemos o seguinte:
![]() |
Acabámos de demonstrar como testar um exemplo retirado do site da PrimeFaces. Todos os exemplos podem ser testados desta forma.
Daqui em diante, iremos concentrar-nos apenas em determinados componentes do PrimeFaces. Primeiro, revisitaremos os exemplos estudados com o JSF e substituiremos certas tags JSF por tags do PrimeFaces. A aparência das páginas mudará ligeiramente; elas terão comportamento AJAX, mas os beans associados não precisarão de ser alterados. Em cada um dos próximos exemplos, iremos simplesmente apresentar o código XHTML das páginas e as capturas de ecrã associadas. Os leitores são encorajados 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: Gestor de eventos – Internacionalização – Navegação na página
Este projeto é uma adaptação do projeto JSF [mv-jsf2-02] (secção 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>. Esta tag tem comportamento AJAX por predefinição, o que pode ser desativado definindo o atributo ajax="false". Assim, aqui, as tags <p:commandLink> comportam-se como tags <h:commandLink>: a página será recarregada quando estes links forem clicados.
5.6. Exemplo mv-pf-03: Layout de página utilizando Facelets
Este projeto demonstra a criação de páginas XHTML utilizando os modelos Facelets do exemplo [mv-jsf2-09] (secção 2.11):
![]() |
O projeto NetBeans é o seguinte:
![]() |
- em [1], os ficheiros de configuração do projeto JSF,
- em [2], as páginas XHTML,
- em [3], o bean de suporte para a mudança de idioma,
- em [4], os ficheiros de mensagens,
- em [5], as dependências.
As páginas do projeto baseiam-se na 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 tirar partido da internacionalização que proporciona,
- linha 15: um formulário com o ID do formulário. Este formulário constitui o corpo da página. Dentro deste corpo, existe apenas uma secção dinâmica, nas linhas 28–30. É aqui que a parte variável da página será inserida:
![]() |
- a área emoldurada acima será atualizada através de chamadas AJAX. Para a identificar, incluímo-la num contentor PrimeFaces gerado pela tag <p:outputPanel> (linha 27). E este contentor foi denominado `content` (atributo id). Uma vez que se encontra dentro de um formulário, que é ele próprio um contentor denominado `form`, o nome completo da área dinâmica é `form:content`. O primeiro : indica que partimos da raiz do documento, depois passamos para o contentor denominado «form» e, em seguida, para o contentor denominado «content». Um dos desafios do AJAX é nomear corretamente as áreas a serem atualizadas por uma chamada AJAX. A forma mais simples é consultar 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 form:content (sem os dois pontos à esquerda) e o nome completo :form:content (com os dois pontos à esquerda) referem-se ao mesmo objeto.
Note que as chamadas AJAX (<p:commandButton>, <p:commandLink>) que atualizam a área dinâmica terão o atributo update=":form:content".
A página [index.xhtml] é a única página apresentada 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>
- Linha 8: O modelo para [index.xhtml] é a página [layout.xhtml] que acabámos de discutir.
- Linha 9: esta é a área de ID de conteúdo que é atualizada por [index.html]. Nesta área, existem dois fragmentos:
- o fragmento [page1.xhtml] na linha 11;
- o fragmento [page2.xhtml] na linha 14.
Estes dois fragmentos são mutuamente exclusivos.
- Linha 10: O fragmento [page1.xhtml] é exibido se a solicitação tiver o atributo page1 definido como true ou se o atributo page2 não existir. Este é o caso da primeira solicitação, em que nenhum destes atributos estará presente na solicitação. Neste caso, o fragmento [page1.xhtml] será exibido,
- Linha 11: O fragmento [page2.xhtml] é exibido se a solicitação 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 apresenta o seguinte conteúdo:
![]() |
- Linhas 11 e 12: os dois links para alterar o idioma. Estes dois links acionam chamadas AJAX (ajax=true). Este é o valor padrão. Portanto, não é necessário incluir o atributo ajax=true. Não o faremos no futuro. Note que estes dois links atualizam a área :form:content (atributo update), a que está destacada acima,
- linha 15: um link de navegação AJAX que, mais uma vez, atualiza a área :form:content,
- linha 16: utilizamos a tag <h:setPropertyActionListener> para definir o atributo «page2» na solicitação como «true». Isto fará com que o fragmento [page2.xhtml] (linha 6 abaixo) seja apresentado 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 para [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>
A partir deste exemplo, vamos ter em mente os seguintes pontos para mais tarde:
- vamos utilizar o modelo [layout.xhtml] como modelo de página,
- a área dinâmica será identificada pelo id:form:content e será atualizada através de chamadas AJAX.
5.7. Exemplo mv-pf-04: formulário de entrada
Este projeto é uma adaptação do projeto JSF2 [mv-jsf2-03] (ver secção 2.5):
![]() |
O projeto NetBeans é o seguinte:
![]() |
Acima, em [1], encontram-se as páginas XHTML do projeto. O layout é fornecido pelo modelo [layout.xhtml] discutido anteriormente. A página [index.xhtml] é a única página do projeto. É apresentada na área :form:content. O 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>
Apenas apresenta o fragmento [page1.xhtml]. Isto é equivalente ao formulário discutido no exemplo [mv-jsf2-03]. Recorde-se que o objetivo desse exemplo era apresentar as tags de entrada do JSF. Estas tags foram aqui substituídas por tags do PrimeFaces.
PanelGrid
Para formatar os elementos em [page1.xhtml], utilizamos a tag <p:panelGrid>. Por exemplo, para os dois links de idioma:
<!-- languages -->
<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>
Isto produz o seguinte resultado:
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–12 definem o cabeçalho da tabela:
As linhas 14–25 definem uma linha da tabela:
As linhas 27–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>
palavra-passe
<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>
![]() |
Linha 7: O atributo feedback=true fornece feedback sobre a força [1] da palavra-passe.
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>
![]() |
Linha 7: A tag <p:editor> apresenta um editor de texto rico que permite formatar o texto (tipo de letra, tamanho, cor, alinhamento, etc.). O que é enviado para o servidor é o código HTML do texto introduzido [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>
![]() |
Linha 14: Note que o link [Reset] executa uma atualização AJAX no campo :form:selectManyMenu, que corresponde ao componente na linha 6. No entanto, é importante notar que, durante o POST AJAX, todos os valores do formulário são enviados. Por conseguinte, todo o modelo é atualizado. Com este modelo, no entanto, apenas o campo :form:selectManyMenu é atualizado.
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 é uma adaptação do projeto JSF2 [mv-jsf2-04] (ver secção 2.6):

Este projeto não introduz quaisquer novas tags PrimeFaces em comparação com o projeto anterior. Por conseguinte, não iremos comentá-lo. Está incluído na lista de exemplos disponíveis para o leitor no site do documento.
5.9. Exemplo: mv-pf-06: navegação – sessão – tratamento de exceções
Este projeto é uma adaptação do projeto JSF2 [mv-jsf2-05] (ver secção 2.7):
![]() |
Mais uma vez, este exemplo não introduz quaisquer novas tags PrimeFaces. Iremos apenas comentar 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 têm o atributo ajax=false. Por isso, a página carrega normalmente.
- Observe as linhas 2 e 4 para saber como realizar um redirecionamento.
5.10. Exemplo: mv-pf-07: validação e conversão de dados de entrada
Este projeto é uma adaptação do projeto JSF2 [mv-jsf2-06] (ver secção 2.8):

A aplicação 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> do JSF, a tag <p:message> do PF introduz as seguintes alterações:
- a aparência da mensagem de erro é diferente [1],
- o campo de entrada incorreto é rodeado por uma moldura vermelha [2].
5.11. Exemplo: mv-pf-08: eventos relacionados com alterações no estado do componente
Este projeto é uma adaptação do projeto JSF2 [mv-jsf2-07] (ver secção 2.9):

O projeto JSF introduziu o conceito de ouvintes. A gestão de ouvintes com o PrimeFaces era tratada de forma diferente.
Com o JSF:
Com o PrimeFaces:
- Linha 2: a tag <h:selectOneMenu> sem o atributo valueChangeListener,
- linha 4: a tag <p:ajax> adiciona comportamento AJAX à sua tag pai <h:selectOneMenu>. Por predefinição, reage ao evento «value change» da lista combo1. Ao ocorrer este evento, os valores do formulário a que pertence serão enviados para o servidor através de uma chamada AJAX. O modelo é, portanto, atualizado. Utilizamos este novo modelo para atualizar a lista suspensa identificada como combo2 (linha 10). Note, na linha 4, que a chamada AJAX não executa quaisquer métodos do modelo. Isto é desnecessário aqui. Pretendemos simplesmente atualizar o modelo enviando os valores introduzidos.
5.12. Exemplo: mv-pf-09: Entrada Assistida
Este projeto apresenta tags de entrada específicas do PrimeFaces que facilitam a introdução de determinados tipos de dados:
![]() |
5.12.1. O projeto NetBeans
O projeto NetBeans é o seguinte:
![]() |
O valor do projeto reside em:
- a única página [index.html] por ele apresentada,
- o modelo [Form.java] para essa página.
5.12.2. O modelo
O formulário tem quatro campos de entrada 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 and setters
...
}
As quatro entradas estão associadas aos campos nas linhas 14–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"/>
<!-- calendar -->
...
<!-- slider -->
...
<!-- spinner -->
...
<!-- autocomplete -->
...
</p:panelGrid>
</ui:define>
</ui:composition>
</html>
Vamos dar uma olhada nos quatro campos de entrada.
5.12.4. O calendário
A tag <p:calendar> permite-lhe selecionar uma data a partir de um calendário. Esta tag suporta vários 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>
A linha 2 especifica que a data deve ser apresentada no formato «dd/mm/aaaa» e que o fuso horário é o de Paris. Quando coloca o cursor no campo de introdução, é apresentado um calendário:
![]() |
5.12.5. O cursor
A tag <p:slider> permite introduzir 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: Esta é uma tag <p:inputText> padrão que permite introduzir um número inteiro. Este valor também pode ser introduzido utilizando o controlo deslizante,
- linha 4: a tag <p:slider> está associada à tag de entrada <p:inputText> (através do atributo). Definimos um valor mínimo e máximo para ela.
5.12.6. O spinner
Já apresentámos este 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 seletor permite introduzir um número inteiro entre 1 e 12. Pode introduzir o número diretamente no campo de entrada do seletor ou utilizar as setas para aumentar ou diminuir o número introduzido.
5.12.7. Preenchimento automático
O preenchimento automático consiste em digitar os primeiros caracteres do campo de entrada. Em seguida, aparecem sugestões numa lista suspensa. Pode selecionar uma delas. Este componente é utilizado em vez de listas suspensas quando estas contêm demasiado conteúdo. Suponha que pretende apresentar uma lista suspensa de cidades em França. Isso equivale a vários milhares de cidades. Se permitir que o utilizador digite os três primeiros caracteres do nome da cidade, pode então apresentar-lhe uma lista reduzida de cidades que começam por esses caracteres.
![]() |
O código para este 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 é o que permite o preenchimento automático. O parâmetro de interesse aqui é o atributo completeMethod, cujo valor é o nome de um método no modelo responsável por gerar sugestões com base nos caracteres digitados pelo utilizador. Este método é definido da seguinte forma:
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 digitada pelo utilizador no campo de entrada. Ele devolve uma lista de sugestões,
- linhas 4–6: é construída uma lista de 10 sugestões, utilizando os caracteres recebidos como parâmetros e adicionando um dígito de 0 a 9 a cada um.
5.12.8. A tag <p:growl>
A tag <p:growl> é uma possível alternativa à tag <p:messages>, que exibe mensagens de erro de 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 (POST) do formulário.
Suponhamos que enviemos o seguinte formulário [1]:
![]() |
- Em [2], a tag <p:growl> exibe então as mensagens de erro associadas às entradas incorretas.
5.13. Exemplo: mv-pf-10: dataTable - 1
Este projeto apresenta a tag <p:dataTable>, que é utilizada para apresentar listas de dados

5.13.1. O Projeto NetBeans
O projeto NetBeans é o seguinte:
![]() |
O atrativo do projeto reside em:
- a página única [index.html] apresentada pelo projeto,
- o modelo [Form.java] para essa página e o bean [Person].
5.13.2. O ficheiro de mensagens
O ficheiro [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 [Person] representa uma pessoa:
package forms;
import java.io.Serializable;
public class Personne implements Serializable{
// data
private int id;
private String nom;
private String prénom;
// manufacturers
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);
}
// getter and setters
...
}
O modelo para a 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{
// model
private List<Personne> personnes;
private int personneId;
// manufacturer
public Form() {
// initialization of the list of persons
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 and setters
...
}
- linhas 9-10: o bean tem âmbito de sessão,
- linhas 18–24: o construtor cria uma lista de três pessoas, uma lista que persistirá entre pedidos,
- linha 15: o ID de uma pessoa a ser removida da lista,
- linhas 26–28: o método delete.
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>
Isto produz a seguinte visualização (emoldurada abaixo):
![]() |
- linha 12: gera a tabela apresentada na caixa acima. O atributo value especifica a coleção apresentada pela tabela, neste caso a lista de pessoas do modelo. O atributo emptyMessage é opcional. Especifica a mensagem a apresentar quando a lista estiver vazia. Por predefinição, é «nenhum registo encontrado». Aqui, será:
![]() |
- linhas 13–15: gerar cabeçalho [1],
- linhas 16–21: gerar coluna [2],
- linhas 22–27: gerar coluna [3],
- linhas 28–33: gerar coluna [4],
- linhas 34-41: gerar coluna [5].
O link [Remover] permite remover uma pessoa da lista. Na linha [38], o método [Form].removePerson executa esta tarefa. Ele precisa saber o ID da pessoa a ser removida. Este é fornecido na linha 39. Na linha 38, utilizámos o atributo action. Noutras ocasiões, utilizámos o atributo actionListener. Não tenho a certeza se compreendo totalmente a diferença funcional entre estes dois atributos. Na prática, no entanto, verificamos que os atributos definidos pelas tags <setPropertyActionListener> são definidos antes de o método designado pelo atributo action ser executado, ao passo que tal não acontece com o atributo actionListener. Em suma, assim que houver parâmetros a enviar para a ação chamada, deve utilizar o atributo action.
O método para remover uma pessoa é o seguinte:
...
@ManagedBean
@SessionScoped
public class Form implements Serializable{
// model
private List<Personne> personnes;
private int personneId;
public void retirerPersonne() {
// search for the selected person
int i = 0;
for (Personne personne : personnes) {
// current person = selected person?
if (personne.getId() == personneId) {
// delete the current person from the list
personnes.remove(i);
// we're done
break;
} else {
// next person
i++;
}
}
}
...
}
5.14. Exemplo: mv-pf-11: dataTable - 2
Este projeto apresenta uma tabela que exibe uma lista de dados onde é possível selecionar uma linha:
![]() |
Ao selecionar uma linha na tabela, são enviadas informações sobre a linha selecionada para o modelo durante a solicitação POST. Como resultado, já não é necessário um link [Remover] para cada 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 o 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 entre os modos de seleção única ou múltipla. Aqui, optámos por selecionar apenas uma única linha,
- linha 13: o atributo rowkey designa um atributo dos elementos exibidos que permite que sejam selecionados de forma única. Aqui, escolhemos o ID da pessoa selecionada,
- linha 13: o atributo selection designa o atributo do modelo que receberá uma referência à pessoa selecionada. Graças ao atributo rowkey anterior, é possível calcular uma referência à pessoa selecionada no lado do servidor. Não dispomos dos detalhes do método utilizado. Podemos imaginar que a coleção é percorrida sequencialmente em busca do elemento correspondente ao rowkey selecionado. Isto significa que, se o método que associa o rowkey à seleção for mais complexo, então este método não é utilizável,
Dito isto, o método [Form].removePerson evolui da seguinte forma:
...
@ManagedBean
@SessionScoped
public class Form implements Serializable {
// model
private List<Personne> personnes;
private Personne personneChoisie;
// manufacturer
public Form() {
...
}
public void retirerPersonne() {
// we remove the chosen person
personnes.remove(personneChoisie);
}
// getters and setters
...
}
- linha 9: em cada POST, a referência na linha 9 é inicializada com a referência, na lista da linha 8, da pessoa selecionada,
- na linha 18: isto simplifica o processo de remoção da linha. A pesquisa que realizámos no exemplo anterior foi feita utilizando a tag <dataTable>.
5.15. Exemplo: mv-pf-12: dataTable - 3
Este projeto é semelhante ao anterior. A visualização é notavelmente idêntica:

O projeto NetBeans é idêntico ao anterior, com algumas pequenas diferenças que iremos analisar. O formulário [index.xhtml] sofre as seguintes alterações:
...
<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>
- Linha 6: o atributo rowkey foi removido, mas o atributo selection permanece. A ligação entre os atributos rowkey e selection é agora estabelecida através de uma classe. O atributo value na linha 5 contém agora uma instância da interface PrimeFaces SelectableDataModel<T>. O método [Form].getPeople do modelo é atualizado da seguinte forma:
public DataTableModel getPersonnes() {
return new DataTableModel(personnes);
}
Assim, é adicionado um novo bean ao projeto:
![]() |
Este 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> {
// manufacturers
public DataTableModel() {
}
public DataTableModel(List<Personne> personnes) {
super(personnes);
}
@Override
public Object getRowKey(Personne personne) {
return personne.getId();
}
@Override
public Personne getRowData(String rowKey) {
// list of persons
List<Personne> personnes = (List<Personne>) getWrappedData();
// the key is an integer
int key = Integer.parseInt(rowKey);
// search for the selected person
for (Personne personne : personnes) {
if (personne.getId() == key) {
return personne;
}
}
// we found nothing
return null;
}
}
- linha 7: a classe é uma instância da interface SelectableDataModel. Pelo menos duas classes implementam esta interface: ListDataModel, cujo construtor aceita uma lista como parâmetro, e ArrayDataModel, cujo construtor aceita uma matriz como parâmetro. Aqui, o nosso bean estende a classe ListDataModel,
- linhas 13–15: o construtor recebe a lista de pessoas que gerimos como parâmetro. Este parâmetro é passado para a classe pai,
- linha 18: o método getRowKey desempenha a função do atributo rowkey que foi removido. Deve devolver o objeto que identifica de forma única uma pessoa, neste caso o ID da pessoa,
- linha 23: o método getRowData deve devolver o objeto selecionado com base na sua rowkey. Assim, neste caso, devolve uma pessoa com base no seu ID. A referência obtida desta forma 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 é a rowkey do objeto selecionado pelo utilizador, na forma de uma string,
- linhas 24–35: devolvem a referência à pessoa cujo ID foi recebido. Esta referência será atribuída ao modelo [Form].personneChoisie. O método [retirerPersonne] permanece, portanto, inalterado:
public void retirerPersonne() {
// on enlève la personne choisie
personnes.remove(personneChoisie);
}
Esta é a técnica a utilizar quando a relação entre os atributos **rowkey e **selection não é uma simples relação de propriedade-objeto (**rowkey** para **selection**).
5.16. Exemplo: mv-pf-13: dataTable - 4
Este projeto é semelhante ao anterior, exceto que o método para selecionar a pessoa a ser removida muda:

Acima, vemos que o objeto é selecionado através de um menu de contexto (clique com o botão direito do rato). É solicitada uma confirmação da eliminação:
![]() |
O formulário [index.xhtml] altera-se da seguinte forma:
...
<ui:composition template="layout.xhtml">
<ui:define name="contenu">
<!-- title -->
<h2><h:outputText value="#{msg['app.titre2']}"/></h2>
<!-- contextual menu -->
<p:contextMenu for="personnes">
<p:menuitem value="#{msg['form.supprimer']}" onclick="confirmation.show()"/>
</p:contextMenu>
<!-- dialog box -->
<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) a dataTable na linha 21 (atributo id). Este menu de contexto aparece quando clica com o botão direito do rato na tabela de pessoas,
- linha 10: o nosso menu tem apenas uma opção (tag menuItem). Quando esta opção é clicada, o código JavaScript no atributo onclick é executado. O código JavaScript [confirmation.show()] exibe a caixa de diálogo da linha 14 (atributo widgetVar). É o 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 é eliminada (atributo action), e a caixa de diálogo é fechada (atributo oncomplete). O atributo oncomplete é código JavaScript que é executado assim que a ação do lado do servidor tiver sido executada,
- linha 17: exibe [5]. Quando clicado, a caixa de diálogo fecha e a pessoa não é eliminada.
5.17. Exemplo: mv-pf-14: dataTable - 5
Este projeto demonstra que é possível receber uma resposta do servidor após a execução de uma chamada AJAX. Para tal, utilizamos o atributo oncomplete da chamada AJAX:
![]() |
O formulário [index.xhtml] é alterado da seguinte forma:
...
<ui:composition template="layout.xhtml">
<ui:define name="contenu">
...
<!-- dialog box 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) {
// erreur ?
if(args.msgErreur) {
alert(args.msgErreur);
}
}
</script>
...
</p:dataTable>
</ui:define>
</ui:composition>
</html>
- linha 7: o atributo oncomplete chama a função JavaScript nas linhas 13–18,
- linha 13: a assinatura do método deve ser esta. args é um dicionário que o modelo do lado do servidor pode preencher,
- linha 15: verificamos se o dicionário args tem um atributo chamado «msgError». Se tiver, é exibido (linha 16).
No modelo, o método [removePerson] evolui da seguinte forma:
public void retirerPersonne() {
// suppression aléatoire
int i = (int) (Math.random() * 2);
if (i == 0) {
// on enlève la personne choisie
personnes.remove(personneChoisie);
} else {
// on renvoie une erreur
String msgErreur = Messages.getMessage(null, "form.msgErreur", null).getSummary();
RequestContext.getCurrentInstance().addCallbackParam("msgErreur", msgErreur);
}
}
- linha 3: gerar um número aleatório 0 ou 1,
- linhas 4–6: se for 0, a pessoa selecionada pelo utilizador é removida da lista de pessoas,
- linha 9: caso contrário, é criada 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 adiciona o atributo denominado «msgError» ao dicionário args que mencionámos anteriormente, com o valor de msgError construído na linha 9. Este atributo é então recuperado pelo método JavaScript em [index.xhtml]:
<!-- Javascript -->
<script type="text/javascript">
function handleRequest(xhr, status, args) {
// erreur ?
if(args.msgErreur) {
alert(args.msgErreur);
}
}
</script>
5.18. Exemplo: mv-pf-15: a barra de ferramentas
Neste projeto, estamos a criar uma barra de ferramentas:
![]() |
A barra de ferramentas é o componente apresentado na caixa acima. É criada utilizando o seguinte código XHTML [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">
<!-- title -->
<h2><h:outputText value="#{msg['app.titre2']}"/></h2>
<!-- toolbar-->
<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 de ferramentas,
- 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 apresentam a vista abaixo:
![]() |
- linha 2: exibe [1],
- linha 3: exibe um espaço de 30 píxeis [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] utilizado para eliminar a pessoa selecionada da lista suspensa. O botão possui um ícone. Estes ícones são do jQuery UI. Pode encontrar uma lista dos mesmos no URL [http://jqueryui.com/themeroller/] [6]:
![]() |
- para encontrar o nome de um ícone, basta passar o rato por cima dele. Este nome é então utilizado no atributo icon do componente <commandButton>, por exemplo icon="ui-icon-trash". Note que acima, o nome atribuído é .ui-icon-trash e que o ponto inicial é removido deste nome no atributo icon,
- Linha 9: cria uma dica de ferramenta para o botão (atributo for). Quando passa o cursor sobre o botão, a mensagem da dica de ferramenta aparece [7].
O modelo associado a estes 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 {
// model
private List<Personne> personnes;
private int personneId;
// manufacturer
public Form() {
// initialization of the list of persons
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() {
// search for the selected person
int i = 0;
for (Personne personne : personnes) {
// current person = selected person?
if (personne.getId() == personneId) {
// delete the current person from the list
personnes.remove(i);
// we're done
break;
} else {
// next person
i++;
}
}
}
// getters and setters
...
}
Os componentes no lado direito 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 vista abaixo:
![]() |
- linhas 6–9: um botão de menu. Contém opções de menu,
- linha 7: a opção para mudar o formulário para francês,
- linha 8: a opção para mudar para inglês.
5.19. Conclusão
Agora sabemos o suficiente para portar a nossa aplicação de exemplo para o PrimeFaces. Abordámos apenas cerca de quinze componentes, enquanto a biblioteca contém mais de 100. Encorajamos os leitores a pesquisar quaisquer componentes em falta 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, podem ser executados [2]. Selecione Tomcat em [3]. Serão então apresentados no navegador interno do Eclipse [3].
![]() |



















































