O JavaServer Faces (JSF) é um dos frameworks mais utilizados para a criação de aplicações web em Java, além do JSF, é possível utilizar o PrimeFaces para a criação de interfaces ricas. Ele é uma especificação para o desenvolvimento de aplicações Web, seguindo o padrão Model View Controler (MVC) em Java, e surgiu como uma alternativa ao Struts, que na época era o principal framework para implementar aplicações nesse padrão de projeto. Sua primeira versão foi disponibilizada em 2004 e em 2013 foi lançada a versão 2.2.

Atualmente, existem diversos frameworks para construção de interfaces ricas com o JSF, entre eles, um dos principais é o Primefaces que disponibiliza diversos componentes. Atualmente esse framework está na versão 5.1 e contém um grande número de componentes, entre eles, o gallery que é um componente para a exibição de uma galeria de imagens.

Este artigo mostrará como implementar uma aplicação com os framework JSF utilizando alguns dos principais componentes do PrimeFaces. A aplicação terá uma tela de cadastro, onde será feito o upload de uma imagem, e uma tela com o componente gallery, onde será exibida uma galeria com diversas imagens cadastradas. As imagens serão armazenadas em um banco de dados MySQL.

Configurando o projeto com o Maven

Para facilitar a configuração do projeto será utilizado o Maven. Para a criação desse projeto serão necessárias as dependências do conector com o MySQL, as bibliotecas do PrimeFaces e também do JSF. Para a biblioteca do PrimeFaces também é necessário adicionar as informações do repositório desse framework. São necessárias ainda, as dependências commons-io e commons-fileupload, utilizadas pelo componente de upload de arquivos do PrimeFaces. A Listagem 1 mostra o arquivo pom.xml do projeto criado.


<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
     http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.devmedia</groupId>
     <artifactId>primefaces</artifactId>
     <version>0.0.1</version>
     <packaging>war</packaging>
 
     <dependencies>
          <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.6</version>
                <scope>compile</scope>
          </dependency>
          <dependency>
                <groupId>org.primefaces</groupId>
                <artifactId>primefaces</artifactId>
                <version>5.1</version>
                <scope>compile</scope>
          </dependency>
          <dependency>
                <groupId>org.glassfish</groupId>
                <artifactId>javax.faces</artifactId>
                <version>2.1.13</version>
                <scope>compile</scope>
          </dependency>
        <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.4</version>
          </dependency>
          <dependency>
                <groupId>commons-fileupload</groupId>
                <artifactId>commons-fileupload</artifactId>
                <version>1.3.1</version>
          </dependency>
     </dependencies>
     <repositories>
          <repository>
                <id>prime-repo</id>
                <name>PrimeFaces Maven Repository</name>
                <url>http://repository.primefaces.org</url>
                <layout>default</layout>
          </repository>
     </repositories>
</project>
Listagem 1. Configurando o projeto com o PrimeFaces 5

Depois de configurar as dependências do projeto, é necessário configurar a aplicação para usar o framework JSF e, como o projeto é de uma aplicação Web, necessitamos criar o arquivo web.xml. O passo mais importante é configurar o Faces Servlet, que utiliza a classe javax.faces.webapp.FacesServlet, e configurar o mapeamento das URL’s que serão tratadas pelo JSF, no caso, todos os endereços que terminarem com *.xhtml. Também foi configurado que caso aconteça algum erro na aplicação, a requisição seja redirecionada para a página inicial da aplicação. A Listagem 2 mostra o código do arquivo web.xml.


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
   <display-name>com.devmedia.primefaces</display-name>
   <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>*.xhtml</url-pattern>
   </servlet-mapping>

   <filter>
        <filter-name>PrimeFaces FileUpload Filter</filter-name>
        <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
   </filter>
   <filter-mapping>
        <filter-name>PrimeFaces FileUpload Filter</filter-name>
        <servlet-name>Faces Servlet</servlet-name>
   </filter-mapping>
   <welcome-file-list>
        <welcome-file>/index.xhtml</welcome-file>
   </welcome-file-list>
   <error-page>
        <exception-type>javax.faces.application.ViewExpiredException</exception-type>
        <location>/index.xhtml</location>
   </error-page>
</web-app>
Listagem 2. Configuração do Web.xml do projeto

Para executar a aplicação é necessário um servidor de aplicação, que pode ser o JBoss, o Jetty ou qualquer outro que execute aplicações web Java. Para o desenvolvimento desse artigo foi utilizado o Tomcat 8.

Criando a aplicação

Depois de todas as configurações realizadas é iniciado o desenvolvimento da aplicação. O primeiro passo é a criação da classe que representara os objetos que serão cadastrados no banco de dados. A Listagem 3 exibe o código da classe Local, que é a entidade dos objetos que serão salvos no MySQL. Essa entidade tem os atributos:

  • id, que é um simples identificador dos objetos;
  • o nome, que representa o nome do local;
  • a cidade, que é a cidade de um local;
  • o país, que é o nome do pais de um local;
  • um array de bytes, que é onde será armazenada a imagem que será enviada por upload e;
  • a dataCadastro, que receberá a data em que o local foi cadastrado no banco de dados.

package com.devmedia.model;
 
import java.util.Date;
 
public class Local {
     
     private int id;
     private String nome;
     private String cidade;
     private String pais;
     private byte[] imagem;
     private Date dataCadastro;
     
     public int getId() {
          return id;
     }
     public void setId(int id) {
          this.id = id;
     }
     public String getNome() {
          return nome;
     }
     public void setNome(String nome) {
          this.nome = nome;
     }
     public String getCidade() {
          return cidade;
     }
     public void setCidade(String cidade) {
          this.cidade = cidade;
     }
     public String getPais() {
          return pais;
     }
     public void setPais(String pais) {
          this.pais = pais;
     }
     public byte[] getImagem() {
          return imagem;
     }
     public void setImagem(byte[] imagem) {
          this.imagem = imagem;
     }
     public Date getDataCadastro() {
          return dataCadastro;
     }
     public void setDataCadastro(Date dataCadastro) {
          this.dataCadastro = dataCadastro;
     }
}
Listagem 3. Classe Local

Como a aplicação salvará os dados no banco de dados MySQL, é necessário criar essa tabela no banco de dados, por isso, a Listagem 4 mostra o código SQL para a criação da tabela local. As colunas criadas são as mesmas dos atributos da classe Local. No desenvolvimento dessa aplicação foi utilizado o banco de dados MySQL, mas qualquer outro banco pode ser utilizado, bastando alterar o pom.xml para adicionar a dependência do conector de outro banco, e alterar a String de conexão com o banco de dados.


CREATE DATABASE local;
 
use local;
 
CREATE TABLE local (
     id INT PRIMARY KEY,
     nome VARCHAR(30),
     cidade VARCHAR(30),
     pais VARCHAR(30),
     imagem BLOB,
     data_cadastro TIMESTAMP
);
Listagem 4. Código SQL para a criação da tabela Local

A aplicação criada terá métodos para inserir e para recuperar locais no banco de dados. A Listagem 5 mostra o código da classe que faz todos os acessos ao banco de dados, o construtor da classe que faz a conexão com o banco de dados passando o nome, o usuário e a senha do banco de dados utilizado. O método closeConnection, simplesmente fecha a conexão com o banco de dados.

O método insertLocal insere no banco de dados um local passado como parâmetro. Para isso, foi criado um PreparedStatement, que recebe o SQL que será executado e o número de parâmetros que devem ser passados para a query. Logo depois, esses parâmetros são passados para a query. Depois o insert é executado e, se o local for cadastrado com sucesso, o método retorna true; caso contrário, é criado um log com a mensagem de erro e o método retorna false.

O método listaLocais recupera todos os locais cadastrados no banco e coloca no retorno do método, inclusive a imagem do local cadastrado. O primeiro passo para isso é criar um objeto do tipo Statement e passar como parâmetro para esse objeto o comando SQL da busca. A consulta do exemplo é bastante simples e retorna todos os locais cadastrados na tabela local.


package com.devmedia.model;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
 
import com.devmedia.model.Local;
 
public class Connect {
     
     Connection con = null;
 
     public Connect() throws SQLException {
 
          try {
                Class.forName("com.mysql.jdbc.Driver");
                System.out.println("Instalou driver");
          } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
          }
 
          String url = "jdbc:mysql://localhost:3306/local";
          String user = "root";
          String password = "eduardo73";
          con = DriverManager.getConnection(url, user, password);
     }
 
     public void closeConnection() throws SQLException {
          con.close();
     }
 
     public boolean insertLocal(Local local) {
 
          
          try {
 
                PreparedStatement preparedStatement = con
                  .prepareStatement("insert into local(id, nome, cidade, 
                  pais, imagem, data_cadastro) values(?,?,?,?,?,?)");
                preparedStatement.setInt(1, local.getId());
                preparedStatement.setString(2, local.getNome());
                preparedStatement.setString(3, local.getCidade());
                preparedStatement.setString(4, local.getPais());
                preparedStatement.setBytes(5, local.getImagem());
                preparedStatement.setDate(6, new java.sql.Date(new Date().getTime()));
 
                preparedStatement.execute();
                return true;
          } catch (SQLException ex) {
                Logger lgr = Logger.getLogger(Connect.class.getName());
                lgr.log(Level.SEVERE, ex.getMessage(), ex);
                return false;
 
          }
     }
 
     public List<Local> listaLocais() {
 
          ArrayList<Local> lista = new ArrayList<Local>();
 
          Statement st = null;
          ResultSet rs = null;
 
          try {
                st = con.createStatement();
                String sql = "select * from local ";
                rs = st.executeQuery(sql);
 
                while (rs.next()) {
 
                     Local local = new Local();
                     local.setId(rs.getInt(1));
                     local.setNome(rs.getString(2));
                     local.setCidade(rs.getString(3));
                     local.setPais(rs.getString(4));
                     local.setImagem(rs.getBytes(5));
                     local.setDataCadastro(rs.getDate(6));
                     lista.add(local);
                }
 
          } catch (SQLException ex) {
                Logger lgr = Logger.getLogger(Connect.class.getName());
                lgr.log(Level.SEVERE, ex.getMessage(), ex);
 
          } finally {
                try {
                     if (rs != null) {
                          rs.close();
                     }
                     if (st != null) {
                          st.close();
                     }
                     if (con != null) {
                          con.close();
                     }
 
                } catch (SQLException ex) {
                     Logger lgr = Logger.getLogger(Connect.class.getName());
                     lgr.log(Level.WARNING, ex.getMessage(), ex);
                }
          }
          return lista;
     }
}
Listagem 5. Classe de conexão com o banco de dados

A Listagem 6 mostra o código do ManagedBean criado para controlar o cadastro e a listagem das imagens dos Locais para serem exibidos na galeria de imagens.

ManagedBean são as classes que conectam o código Java, com o código da visão e para criar uma classe desse tipo é necessário utilizar a anotação @ManagedBean e dizer qual o nome desse ManagedBean. O nome é importante, pois nas telas, para acessar a classe, será utilizado o nome usado nessa anotação.

O primeiro método desse ManagedBean é o método cadastraLocal, que recebe um local que foi criado na tela de cadastro. Depois é criada uma conexão com o banco de dados e finalmente é chamado o método insereLocal da classe Connect, que faz a inserção do local no banco de dados. Se o cadastro for efetuado com sucesso, é retornada uma mensagem de sucesso para o usuário, caso contrário, uma mensagem informando o usuário do erro é enviada.

O método listarLocais recuperar todos os locais que estão cadastrados no banco de dados e retorna para a tela que chamou esse método. No JSF, todos os métodos que retornam objetos para a tela devem ter o nome iniciado com get. Ainda no ManagedBean são criados os métodos get e set para o atributo Local da classe. Esse método será utilizado para retornar as imagens.


package com.devmedia.managedbeans;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
 
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
 
import org.primefaces.event.FileUploadEvent;
 
import com.devmedia.model.Connect;
import com.devmedia.model.Local;
 
@ManagedBean(name = "LocalMB")
@ViewScoped
public class LocalManagedBean {
 
     private Local local = new Local();
    
     private List<String> imagens;
          
    public void handleFileUpload(FileUploadEvent event) {
        
     local.setImagem(event.getFile().getContents());
     
     FacesMessage message = new FacesMessage("Succesful", 
     event.getFile().getFileName() + " is uploaded.");
        FacesContext.getCurrentInstance().addMessage(null, message);
    }
    
     public String cadastraLocal() throws SQLException {
 
          Connect con = new Connect();
 
          if (con.insertLocal(local)) {
            FacesContext.getCurrentInstance().addMessage(
                null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "Sucesso!",
                  "Local cadastrado com sucesso!"));
          } else {
            FacesContext.getCurrentInstance().addMessage(
                null,
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erro!",
                  "Erro no cadastro de local!"));
 
          }
          con.closeConnection();
 
          return "";
     }
 
     public List<String> getImages() throws SQLException, IOException {
          
          Connect con = new Connect();
          List<Local> listaLocais = con.listaLocais();
          List<String> images = new ArrayList<String>();
          
          String path = FacesContext.getCurrentInstance()
          .getExternalContext().getRealPath("/temp");
          
          for (Local local : listaLocais) {
                FileOutputStream fos = new FileOutputStream(path + "/" 
                + local.getNome() + ".jpg");
                fos.write(local.getImagem());
                fos.close();
                images.add(local.getNome() + ".jpg");
          }
          
          return images;
     }
 
     public Local getLocal() {
          return local;
     }
 
     public void setLocal(Local local) {
          this.local = local;
     }
 
}
Listagem 6. Managed Bean para cadastrar e listar Locais

Criando a tela de cadastro de local

Depois de criados o ManagedBean, é possível criar a tela de cadastro de local que terá:

  • um componente panelGrid, que organiza a tela em uma tabela;
  • um componente spinner, que é um campo de entrada de dados para números onde será cadastrado o id do local;
  • dois componentes inputText para o cadastro dos campos nome e cidade e país,
  • um componente fileUpload para cadastrar uma imagem do local cadastrado.

A Listagem 7 exibe o código para a criação dessa tela.

Ainda na tela de cadastro existe um botão que é representado pelo componente commandButton.O texto do atributo value indica o texto que aparecerá no botão, o atributo opcional icon indica um ícone para aparecer no botão. O atributo action indica qual o método do ManagedBean que será executado e o atributo update indica que o componente de exibição de mensagens deve ser atualizado depois de cada cadastro.


<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:p="http://primefaces.org/ui">
 
<h:head>
 
</h:head>
 
<h:body>
 <h:form>
  <p:messages id="messages" />
  <p:panelGrid columns="2">
        <p:outputLabel for="id" value="ID:" />
        <p:spinner id="id" value="#{LocalMB.local.id}" />
        
        <p:outputLabel for="nome" value="Nome:" />
       <p:inputText id="nome" value="#{LocalMB.local.nome}" />
        
        <p:outputLabel for="cidade" value="Cidade:" />
        <p:inputText id="cidade" value="#{LocalMB.local.cidade}" />
        
        <p:outputLabel for="pais" value="Pais:" />
        <p:inputText id="pais"
             value="#{LocalMB.local.pais}" />
             
        <p:fileUpload fileUploadListener="#{LocalMB.handleFileUpload}" 
        mode="advanced" dragDropSupport="false"
        update="messages" sizeLimit="1000000" fileLimit="3" 
        allowTypes="/(\.|\/)(gif|jpe?g|png)$/" />
        
        <p:commandButton value="Cadastrar" icon="ui-icon-star" 
        action="#{LocalMB.cadastraLocal}" update="messages">
        </p:commandButton>

  </p:panelGrid>
 </h:form>
</h:body>
</html>
Listagem 7. Tela de cadastro de Local

A Figura 1 mostra a tela criada no código da Listagem 7, que tem um campo para o cadastro de cada atributo da classe Local, além do campo para o upload da imagem. Acima do formulário é mostrada a mensagem de sucesso, indicando que o cadastro do local foi realizado com sucesso.

Tela de cadastro de usuários
Figura 1. Tela de cadastro de usuários

O último passo é a criação da tela que mostra a galeria de imagens. Para isso, é utilizado o componente gallery do Primefaces, que é um componente bastante poderoso e que disponibiliza um grande número de funcionalidades com uma implementação bastante simples. O atributo value indica o método do ManagedBean de onde virão as imagens, no caso, o método getImagems do ManagedBean LocalMB. O atributo var indica o nome da variável para ser utilizada na recuperação dos dados dos objetos. O atributo showCaption indica que deve ser mostrado na galeria uma descrição da imagem.

A Listagem 8 mostra o código para a criação da tela da galeria de imagens.


<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:p="http://primefaces.org/ui">
 
<h:head>
 
</h:head>
 
<h:body>
   <h:form>
      <p:galleria value="#{LocalMB.images}" var="image" panelWidth="500"
          panelHeight="313" showCaption="true">
          <p:graphicImage value="temp/#{image}"
               alt="Image Description for #{image}" title="#{image}" />
      </p:galleria>
   </h:form>
</h:body>
</html>
Listagem 8. Tela de listagem de Usuários

A Figura 2 mostra a tela da galeria de imagens criada na Listagem 8. Como no banco de dados haviam três locais cadastrados, a galeria exibe as três imagens pequenas e o usuário pode selecionar a imagem que quer visualizar.

 Tela da galeria de imagens
Figura 2. Tela da galeria de imagens

Este artigo mostrou como criar uma aplicação simples com o JavaServer Faces, o PrimeFaces e o MySQL para o cadastro de imagens, e a exibição de uma galeria de imagens com o componente gallery do Primefaces. O projeto utilizou a versão mais recente do PrimeFaces, que é hoje um dos principais frameworks para a criação de interfaces ricas do JSF.