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>
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>
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;
}
}
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
);
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;
}
}
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;
}
}
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>
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.

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>
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.

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.