Para tratarmos do PrimeFaces, precisamos rever alguns conceitos sobre as tecnologias e o desenvolvimento web, os quais serão utilizados para o desenvolvimento deste projeto, que consiste em um projeto Web com o framework JavaServer Faces, baseado nas especificações do Java EE e rodará sobre um servidor de aplicação Glassfish.

Servidor de Aplicação

Um servidor de aplicação é um software que fornece um ambiente integrado para a implantação, execução personalizada e gerenciamento eficaz de aplicativos de negócios baseados em servidores, aplicativos de alta disponibilidade, alta performance e distribuídos. Isso nos permite hospedar sites e/ou aplicativos e distribuí-los, na internet ou em uma rede local. Outra vantagem é que isto permite ao gestor do serviço o monitoramento dos serviços disponibilizados. Desta forma estes projetos passam a operar sobre uma arquitetura cliente-servidor, como podemos observar na Figura 1.

Modelo cliente-servidor
Figura 1. Modelo cliente-servidor

Podemos observar com mais detalhes o fluxo das informações desta arquitetura na Figura 2. O Servidor Web pode englobar uma ou mais máquinas físicas ou virtuais, o que lhe permite delegar tarefas a especialistas, por exemplo, uma máquina pode ser a responsável pelo gerenciamento do Banco de Dados e a outra pelo software do servidor de aplicação.

comunicação com um servidor web
Figura 2. Comunicação com um servidor web

A oferta de servidores de aplicação é grande, dentre as melhores opções gratuitas para Java temos o Glassfish da Oracle, o TomEE da Apache, o JBoss da Red Hat e o WildFly, também da Red Hat. Cada um com seus pontos fortes e fracos, mas isso não será abordado neste artigo. A opção escolhida para este projeto é o Glassfish, pelo fato de que será utilizada a IDE Netbeans e ambos interoperam muito bem, sem a necessidade de demais configurações.

Glassfish

O Glassfish é um servidor de aplicação Open-Source. O projeto foi iniciado pela Sun Microsystems e agora é patrocinado pela Oracle Corporation. Ele implementa as especificações Java EE, além de suportar Enterprise JavaBeans, JPA, JavaServer Faces, JMS, RMI, JavaServer Pages, servlets, etc. Isto permite aos desenvolvedores criar aplicativos empresariais que são portáteis e escaláveis, e que se integram com tecnologias legadas. Componentes opcionais também podem ser instalados para serviços adicionais.

Java EE

A plataforma Java EE (Enterprise Edition) estende a plataforma SE do Java e é o padrão para desenvolvimento de aplicativos empresariais entre a comunidade Java. A plataforma fornece um ambiente de execução e uma API para desenvolvimento de softwares empresariais incluindo serviços de rede e web, multicamadas, escaláveis, confiáveis e aplicações de rede seguras e web services. Atualmente a versão mais recente é a Java EE 7.

JavaServer Faces

De maneira simplificada, JSF é um framework web MVC para a construção de interfaces de usuário baseadas em componentes. Projetado para ser flexível, ele estabelece um padrão para a construção de interfaces com o usuário do lado do servidor. A arquitetura define claramente uma separação entre a lógica da aplicação e a apresentação, enquanto torna mais fácil ligar a camada de apresentação ao código do aplicativo.

PrimeFaces

O PrimeFaces é um popular framework para projetos JSF que pode ser usado para desenvolver rapidamente aplicações sofisticadas para empresas ou no desenvolvimento de sites padrão. Tecnicamente, o PrimeFaces é uma biblioteca de componentes de interface gráfica para as aplicações web baseadas em JSF. Com ele é possível aumentar a produtividade do desenvolvedor e a experiência do usuário com a aplicação, pois torna menos árduo criar uma aplicação que seja exibida corretamente na maioria dos dispositivos, sem contar que é muito flexível e personalizável, com uma grande opção de componentes para os mais diversos fins.

Além deste, temos outros frameworks para a mesma finalidade, dentre eles o IceFaces e o RichFaces, porém com menos popularidade, sem contar que o PrimeFaces está em alta comparado aos seus concorrentes que estão cada vez mais perdendo espaço. É possível comprovar isso com uma simples busca no Google Trends, como mostra a Figura 3.

Popularidade dos frameworks através do Google Trends
Figura 3. Popularidade dos frameworks através do Google Trends

Verificando o Ambiente

Para começar a codificar o sistema, não é necessária nenhuma configuração especial ao servidor Glassfish. Basta instalar o Netbeans com suporte à tecnologia Java EE, que por padrão já será instalado o servidor Glassfish pré configurado. Para verificar se seu Netbeans já possui um servidor Glassfish vinculado, basta clicar na aba Serviços e depois no menu Servidores, conforme a Figura 4. E para ver se a instalação do servidor está OK, basta clicar com o botão direito do mouse sobre o servidor e clicar em Iniciar. Pode demorar um pouco, mas se aparecer uma setinha verde antes do nome do servidor, é sinal de que ele foi iniciado com sucesso e está pronto para uso.

Servidor Glassfish vinculado ao Netbeans
Figura 4. Servidor Glassfish vinculado ao Netbeans

Criando o Projeto

Para darmos início à codificação do projeto, cria-se um novo projeto Web, conforme a Figura 5. Na etapa de Servidor e Definições é importante salientar que deve ser escolhido o servidor Glassfish vinculado (caso não apareça nada, é por que não tem servidor Glassfish vinculado, ou nem sequer está instalado o Glassfish) e a versão do Java EE, que neste caso será a última disponível, a versão 7.

Novo Projeto Web
Figura 5. Novo Projeto Web

A próxima etapa é onde se escolhe os frameworks os quais se deseja utilizar. Conforme a Figura 6, escolhemos apenas o framework JavaServer Faces. Feito isto, surgirão novas configurações abaixo e então na aba Componentes é preciso selecionar o PrimeFaces. Pronto, agora é só clicar em finalizar para criar o projeto.

Escolha do framework.
Figura 6. Escolha do framework

É importante considerarmos que não se faz necessário adicionar o componente do PrimeFaces no momento da criação do projeto, nem tanto que está seja a única forma de utilizá-lo. Usar o PrimeFaces em um projeto, consiste apenas em adicionar sua biblioteca ao projeto, para que suas classes sejam reconhecidas e este processo é extremamente simples para qualquer IDE que se esteja utilizando, basta ter em mãos a biblioteca (.jar) do PrimeFaces.

Por padrão, o Netbeans já traz consigo uma versão do PrimeFaces para tornar mais prático este processo, conforme foi feito anteriormente. Mas salvo que em outros casos é necessário antes fazer o download da biblioteca e posteriormente adicioná-la manualmente ao projeto. A biblioteca pode ser baixada gratuitamente do site principal (vide seção Links): na seção Community Downloads escolha a última versão binária. Com o .jar em mãos, basta adicionar a biblioteca ao projeto, lembrando que este processo é apenas para quem não seguiu o procedimento da Figura 6 ou possui um projeto web que não tenha o PrimeFaces adicionado.

Codificando

Com o projeto criado, já é possível executá-lo. Caso o servidor Glassfish ainda não esteja em execução, ele antes será inicializado, o que pode demandar algum tempo, posteriormente o projeto automaticamente será implantado e o navegador padrão (é possível testar com outros) será aberto na página do projeto, neste caso será a página index, por não ter sido especificada outra, como mostra a Figura 7.

Página index.xhtml do projeto
Figura 7. Página index.xhtml do projeto

Para acessar o sistema web manualmente, precisamos dispor da URL de acesso ou conhecer como ela é formada. Como estamos acessando um endereço local, começamos por localhost, posteriormente vem a porta de acesso, que por padrão é 8080 nos servidores de aplicação: portanto temos agora localhost:8080, mas ainda é necessário informar qual é a aplicação que se deseja acessar no servidor. Basta então acrescentarmos o nome do projeto, que neste caso é DevMedia (letras maiúsculas e minúsculas serão diferenciadas). Tem-se agora a URL completa para acessar a index do sistema: http://localhost:8080/DevMedia.

O projeto ao ser criado já disponibiliza uma página index, assim como mostra a Figura 7, e outra página com um modelo do PrimeFaces, como mostra a Figura 8.

Página welcomePrimefaces.xhtml do projet
Figura 8. Página welcomePrimefaces.xhtml do projeto

Agora precisamos compreender um pouco mais sobre estas páginas para que possamos efetivamente começar a codificá-las. Em um projeto JSF as páginas web são escritas em arquivos .xhtml. Em poucas palavras, o XHTML é uma espécie de junção entre o HTML e oXML.

O XML é uma especificação bastante rígida, por exemplo: quando os navegadores encontram um erro no HTML comum, como uma tag sem o, ou sea, uma tag abrindo, mas sem o devido fechamento, o erro é "corrigido" automaticamente e, com isso, o usuário geralmente consegue visualizar a página normalmente; já com o XML, um erro desse tipo faz a aplicação parar. Além disso, cada navegador corrige o erro da sua forma, o que significa que o que você vê funcionando em um dispositivo pode virar bagunça em outro. Desta forma, ao combinar HTML com XML,o XHTML resultante é a garantia de que seu site será exibido exatamente como você o desenvolveu, independente do dispositivo. Isso evita o uso dehackspara corrigir problemas de exibição em determinados navegadores e ainda deixa seu código organizado para atualizações futuras. Portanto, ao desenvolvermos nossas páginas, não podemos esquecer de fechar nenhuma tag.

Dentro deste xhtml, teremos inicialmente a abertura da tag html com seus Namespaces (xmlns), conforme mostra a Listagem 1. A grosso modo podem ser comparadas com as importações de um arquivo Java, mas ao mesmo tempo fornecem nomes abreviados às bibliotecas de componentes utilizadas. Isso se faz necessário para nos facilitar o uso dos componentes do PrimeFaces. Desta forma, toda em que vou usar um componente do PrimeFaces, será preciso apenas colocar no início da tag a abreviação p, por exemplo: <p:nomedocomponente>.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:p="http://primefaces.org/ui">
 
    <f:view contentType="text/html">
        <h:head>
            <f:facet name="first">
                <meta content='text/html; charset=UTF-8' 
                http-equiv="Content-Type"/>
                <title>PrimeFaces</title>
            </f:facet>
        </h:head>
 
        <h:body>
 
            <p:layout fullPage="true">
 
                <p:layoutUnit position="north" size="100" 
                resizable="true" closable="true" collapsible="true">
                    Header
                </p:layoutUnit>
 
                <p:layoutUnit position="south" size="100" 
                closable="true" collapsible="true">
                    Footer
                </p:layoutUnit>
 
                <p:layoutUnit position="west" size="175" 
                header="Left" collapsible="true">
                    <p:menu>
                        <p:submenu label="Resources">
                            <p:menuitem value="Demo" 
                            url="http://www.primefaces.org/showcase-labs/ui/home.jsf" />
                            <p:menuitem value="Documentation" 
                            url="http://www.primefaces.org/documentation.html" />
                            <p:menuitem value="Forum" 
                            url="http://forum.primefaces.org/" />
                            <p:menuitem value="Themes" 
                            url="http://www.primefaces.org/themes.html" />
 
                        </p:submenu>
 
                    </p:menu>
                </p:layoutUnit>
 
                <p:layoutUnit position="center">
                    Welcome to PrimeFaces
                </p:layoutUnit>
 
            </p:layout>
 
        </h:body>
 
    </f:view>
</html>
Listagem 1. Código fonte do arquivo welcomePrimefaces.html

Podemos começar a codificar nosso sistema para um propósito em específico. Será desenvolvido um sistema que permita cadastrar contatos com o devido nome da pessoa e e-mail. O sistema será organizado em uma página principal com um menu de acesso e uma página de cadastro de contatos.

Antes de começarmos a escrever código, há uma questão muito importante a ser frisada, de que no site oficial do PrimeFaces estão disponíveis exemplos de uso de cada um de seus componentes, com o respectivo código xhtml e Java. Os exemplos podem ser acessados no site principal (vide seção Links).

Começaremos por modificar nossa página index criando um menu de acesso às demais páginas do sistema, conforme Listagem 2. Já a página welcomePrimefaces.html pode ser descartada, pois não terá função no sistema.


<?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">
 
    <h:head>
        <title>DevMedia - Menu</title>
    </h:head>
    <h:body>
        <!--A tag form é necessária para criar o menu-->
        <h:form>
            <!--Menu-->
            <p:menu>
                <p:submenu label="Cadastros">
                    <!--Este é o ítem que permitirá clicar e navegar 
                    para a página de Cadastro de Contatos.
                    O atributo value é usado para definir o texto que 
                    será exibido sobre o menu.
                    O atributo outcome é usado para apontar a página 
                    que será chamada quando o menu for acionado.
                    O atributo icon define uma imagem para o menu, 
                    neste caso usando da coleção ui-icon que já está 
                    presente na biblioteca.-->
                    <p:menuitem value="Contatos" outcome="contatos" 
                    icon="ui-icon-person" />
                </p:submenu>
            </p:menu>
        </h:form>
    </h:body>
</html>
Listagem 2. Página index.xhtml

Para que as páginas renderizem corretamente com os comentários entre os trechos de código, precisamos configurar o projeto para ignorá-los, ou simplesmente remover os comentários da página xhtml. O trecho de código da Listagem 3 deve ser adicionado ao arquivo de configurações do projeto, web.xml, que se localiza na pasta WEB-INF.


<context-param>  
    <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>  
    <param-value>true</param-value>  
</context-param> 
Listagem 3. Código para ignorar comentários na renderização

Desta forma, nosso arquivo de configurações web.xml fica conforme a Listagem 4. Neste arquivo é possível alternar a página padrão de início, que por padrão é a index. Além disso, tem o parâmetro javax.faces.PROJECT_STAGE que, por padrão, vem definido como Development, indicando que o projeto está em fase de desenvolvimento, portanto, caso ocorra algum erro, ele será exibido no formulário web. Porém quando este projeto for para produção, isto não é legal, logo, o parâmetro deve ser alterado para Production, o que fará com que o usuário não veja os detalhes técnicos dos erros.


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>faces/index.xhtml</welcome-file>
    </welcome-file-list>
    
    <context-param>  
        <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>  
        <param-value>true</param-value>  
    </context-param>  
</web-app>
Listagem 4. Arquivo web.xml.

Criamos então uma classe Contato que define nosso tipo de informação a ser armazenada e manipulada, conforme Listagem 5.


package br.com.devmedia.model;
 
import java.io.Serializable;
 
public class Contato implements Serializable {
 
    private String nome;
    private String email;
 
    public String getNome() {
        return nome;
    }
 
    public void setNome(String nome) {
        this.nome = nome;
    }
 
    public String getEmail() {
        return email;
    }
 
    public void setEmail(String email) {
        this.email = email;
    }
}
Listagem 5. Classe da entidade Contato

Antes de iniciarmos o desenvolvimento do formulário responsável pela manipulação dos dados, precisamos criar a classe Java que será encarregada pelas requisições realizadas a partir do formulário web. Para que isto seja possível, esta classe deverá intermediar a comunicação entre as páginas e o modelo. Para isto usamos Managed Beans, que na prática são classes com a notação @ManagedBean, conforme a Listagem 6.


package br.com.devmedia.bean;
 
import br.com.devmedia.model.Contato;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
 
//Este annotation é necessário para que o formulário possa fazer 
chamadas à métodos desta classe.
//O atributo name server para dar-lhe um nome, o qual será usado 
nos formulários web para acessar dados nesta classe.
@ManagedBean(name = "contatoBean")
 
//Este annotation define o tipo de escopo de sessão para ViewScoped,
 ou seja, a sessão permanece enquanto o formulário permanecer aberto.
@ViewScoped
public class ContatoBean implements Serializable {
 
    //lista para armazenar os dados (apenas para simular um "banco de dados")
    private static final List<Contato> dados = new ArrayList<>();
 
    //atributo que receberá os dados digitados nos campos
    private Contato contato;
 
    public Contato getContato() {
        return contato;
    }
 
    public void setContato(Contato contato) {
        this.contato = contato;
    }
 
    //ao criar a Bean, um novo Contato é instanciado. Isso acontece 
    toda vez que o formulário é carregado. 
    //Isso acontece devido ao tipo de sessão ser ViewScoped
    public ContatoBean() {
        contato = new Contato();
        System.out.println("!");
    }
 
    //Na página, ao clicar em salvar, este método é acionado. Os valores 
    já estão no atributo contato, basta adicioná-lo à lista.
    public void inserir() {
        dados.add(contato);
        contato = new Contato();
    }
 
    public void deletar(Contato contato) {
        dados.remove(contato);
    }
 
    public List<Contato> getContatos() {
        return dados;
    }
}
Listagem 6. Classe ContatoBean

Além do escopo de sessão utilizado, existem outros, como segue:

  • @ApplicationScoped: Este tipo de sessão permanece existente entre todas as interações de todos os usuários, permitindo compartilhar informações entre os usuários.
  • @SessionScoped: Permanece ativo em várias requisições HTTP enquanto durar a sessão do usuário, permitindo compartilhar informações do mesmo usuário entre beans diferentes.
  • @ViewScoped: A sessão permanece enquanto o formulário permanecer aberto. Enquanto a página existir uma instância do ManagedBean existirá.
  • @RequestScoped: Escopo de requisição. Existe durante uma única solicitação/requisição HTTP.
  • @NoneScoped: Indica que não há escopo de sessão definido para a aplicação.
  • @CustomScoped: Escopo personalizado.

Por fim, podemos desenvolver o formulário web de cadastro e listagem dos dados. Na Listagem 7 temos este formulário que permite cadastrar, visualizar e excluir contatos.


<?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">
 
    <h:head>
        <title>DevMedia - Contatos</title>
    </h:head>
    <h:body>
        <h1>Cadastro de Contatos</h1>
        <h:form>
            <h3>Nome</h3>
            <!--Campo que receberá o nome do contato. Ao sair do campo 
            o valor é salvo no atributo contato(nome) da classe ContatoBean-->
            <p:inputText id="nome" value="#{contatoBean.contato.nome}"/>
            <h3>E-Mail</h3>
            <!--Campo que receberá o e-mail do contato. Ao sair do campo o 
            valor é salvo no atributo contato(email) da classe ContatoBean-->
            <p:inputText id="mail" value="#{contatoBean.contato.email}"/>
            <br /><br />
            <!--Botão Salvar, ao ser acionado ele executa o método que está 
            definido na propriedade actionListener 
            e depois atualiza os componentes listado na propriedade update-->
            <p:commandButton value="Salvar" id="salvar" 
            actionListener="#{contatoBean.inserir()}" update="nome, mail, tabela"/>
            <br /><br />
 
            <!--Tabela para exibir os dados.
            Na propriedade value coloca-se o método que retorna a lista de 
            dados a ser exibida.
            A propriedade var serve para dar um nome ao objeto de 
            iteraração da lista. Este nome é usado nas colunas para buscar os 
            valores dos registros-->
            <p:dataTable var="contato" value="#{contatoBean.getContatos()}" 
            id="tabela">
                <!--Coluna Nome-->
                <p:column headerText="Nome">
                <!--aqui define-se que será exibido apenas texto nesta célula, 
                com o componente outputText.
                A propriedade value define o valor a ser exibido, neste caso 
                buscando o nome do contato, lembrando que o contato descrito aqui é o 
                mesmo da propriedade var acima.-->
                    <h:outputText value="#{contato.nome}"></h:outputText>
                </p:column>
 
                <!--Coluna E-Mail-->
                <p:column headerText="E-Mail">
                    <h:outputText value="#{contato.email}"></h:outputText>
                </p:column>
 
                <p:column style="width:100px;text-align: center">
                <!--Nesta coluna será exibido um botão para excluir o registro.
                O botão possui uma ação definida pela propriedade actionListener e 
                logo após atualiza os componentes listados na propriedade update-->
                    <p:commandButton value="Excluir" 
                                     actionListener="#{contatoBean.deletar(contato)}"
                                     update="tabela"/>
                </p:column>
            </p:dataTable>
        </h:form>
    </h:body>
</html>
Listagem 7. Página de cadastro de contatos

Segue na Figura 9 a estrutura expandida do projeto desenvolvido. Seguindo-a, mais as técnicas empregadas, a margem de erro é praticamente nula.

estrutura do projeto
Figura 9. Estrutura do projeto

O desenvolvimento de aplicações web tornou-se fundamental e uma das formas mais práticas de se criar aplicações multiplataforma baseadas na arquitetura cliente-servidor. Neste contexto o framework JSF com a API de componentes do PrimeFaces cria uma excelente plataforma de desenvolvimento fácil, prático e robusto.