O Java Server Faces é uma especificação para o desenvolvimento de aplicações Web, seguindo o padrão Model View Controler (MVC) em Java, essa especificação 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 para o JSF, como o RichFaces, o IceFaces, e principalmente o PrimeFaces, que se destaca por disponibilizar uma grande variedade de componentes. Atualmente esse framework está na versão 5.1. e contém um grande número de componentes de formulários, listagem, menus, entre outros, que facilitam muito o desenvolvimento de interfaces.
O JPA é uma especificação para a persistência de dados em Java utilizando o Mapeamento Objeto-Relacional (ORM – Object Relational Mapping). Uma das principais implementações do JPA é a do framework Hibernate. JPA pode ser utilizado com qualquer banco de dados que tenha um driver para a comunicação com aplicações Java, entre eles, o PostgreSQL, o Oracle, o SQL Server e o MySQL.
Este artigo mostrara como configurar uma aplicação web com o PrimeFaces e o Hibernate, e também como implementar uma tela de login com essas tecnologias. O servidor de banco de dados utilizado no desenvolvimento da aplicação será o MySQL.
Configurando o projeto
Para facilitar a configuração do projeto, será utilizado o Maven. Para a criação desse projeto serão necessárias as dependências das bibliotecas do PrimeFaces, do JSF, do Hibenate e do driver do MySQL. Para a biblioteca do PrimeFaces também é necessário adicionar as informações do repositório desse framework. 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>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.common</groupId>
<artifactId>hibernate-commons-annotations<
/artifactId>
<version>4.0.1.Final</version>
<classifier>tests</classifier>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence<
/groupId>
<artifactId>hibernate-jpa-2.0-api<
/artifactId>
<version>1.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager<
/artifactId>
<version>4.0.1.Final</version>
</dependency>
<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>
</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 com o Maven, é necessário configurar a aplicação para usar o framework JSF, 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 o padrão *.xhtml. Também foi configurado que caso acontece 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>
<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>
Também é necessário configurar o arquivo persistence.xml, que é o arquivo que configura o acesso ao banco de dados com JPA. A Listagem 3 mostra esse arquivo. Algumas configurações importantes desse arquivo são, na tag deve ser definido o nome da unidade de persistência, na tag deve ser definido a implementação utilizada do JPA, no caso o Hibernate, a tag define as classes dos objetos que serão persistidos, nesse exemplo, apenas a classes Usuario será usada. As outras propriedades definem as opções de acesso ao MySQL. A propriedade hibernate.hbm2ddl.auto define que o banco de dados será criado automaticamente caso ele ainda não exista, o que diminui um pouco o trabalho de configuração.
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="usuarios">
<!-- provedor/implementacao do JPA -->
<provider>org.hibernate.ejb.HibernatePersistence<
/provider>
<!-- entidade mapeada -->
<class>com.devmedia.model.Usuario</class>
<properties>
<!-- dados da conexao -->
<property name="javax.persistence.jdbc.driver"
value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url"
value="jdbc:mysql://localhost/user" />
<property name="javax.persistence.jdbc.user"
value="root" />
<property name="javax.persistence.jdbc.password"
value="eduardo73" />
<!-- propriedades do hibernate -->
<property name="hibernate.dialect"
value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<!-- atualiza o banco, gera as tabelas se for preciso -->
<property name="hibernate.hbm2ddl.auto" value="update" />
</properties>
</persistence-unit>
</persistence>
Para projetos configurados com o maven, O arquivo persistence.xml deve obrigatoriamente ficar no diretório /src/main/resources/META-INF do projeto.
Para executar os exemplos criados neste artigo será necessário utilizar um container Web. O PrimeFaces e a JPA podem ser executados em qualquer um que seja compatível com o Java Web, entre eles o Jetty e o Tomcat. No desenvolvimento do artigo foi utilizado o Apache Tomcat, versão 8.0.12.
Desenvolvendo a tela de Login
O primeiro passo para o desenvolvimento da tela de Login, é desenvolver a classe que implementa os objetos que serão persistidos no banco de dados. Como usaremos o JPA, é necessário utilizar as anotações dessa especificação, para que seja feito o mapeamento Objeto-Relacional dos atributos da classe.
A Listagem 4 mostra o código da classe Usuario, que é o objeto que será persistido no banco de dados. A classe tem quatro atributos, que são o Id, o nome de usuário, a senha do usuário e a data do último acesso ao sistema. As principais anotações são @Id, que define que o atributo é o identificador único da classe, a anotação @Column que define diversas opções para a coluna, como o nome da coluna no banco de dados, se ela é uma coluna com valores únicos e se ela pode receber valores nulos e a anotação @Temporal que deve ser utilizada para atributos com o tipo data.
Os campos id e nomeUsuario são únicos, por isso o atributo unique nesses dois atributos tem o valor true, a senha e a data de ultimo acessa não precisam ser únicos, já que dois usuários diferentes podem acessar a aplicação ao mesmo tempo, e também podem ter senhas iguais. Todos os dados do usuário são obrigatórios, menos o ultimoAcesso, os dados obrigatórios devem ter o atributo nullable como false, e os não obrigatórios true.
package com.devmedia.model;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
public class Usuario {
@Id
@Column(name="id", nullable=false, unique=true)
private int id;
@Column(name="userName", nullable=false, unique=true)
private String nomeUsuario;
@Column(name="password", nullable=false, unique=false)
private String senha;
@Column(name="lastAccess", unique=true)
@Temporal(TemporalType.DATE)
private Date ultimoAcesso;
public String getNomeUsuario() {
return nomeUsuario;
}
public void setNomeUsuario(String nomeUsuario) {
this.nomeUsuario = nomeUsuario;
}
public String getSenha() {
return senha;
}
public void setSenha(String senha) {
this.senha = senha;
}
public Date getUltimoAcesso() {
return ultimoAcesso;
}
public void setUltimoAcesso(Date ultimoAcesso) {
this.ultimoAcesso = ultimoAcesso;
}
}
Depois de criar a classe do objeto que será persistido, podemos definir a classe que faz as operações no banco de dados, como incluir, excluir e recuperar dados. Como vamos implementar apenas o login, precisaremos apenas do método que recupera os dados do usuário, caso ele exista. A Listagem 5 mostra o código da classe UsuarioDAO que tem o método getUsuario recebendo os parâmetros nomeUsuario e senha, nesse método é feita uma busca no banco, e caso esse usuário exista, ele é retornado, caso contrário, é retornado null. Quando uma query não retorna resultados, é lançada uma exceção do tipo NoResultException, por isso foi utilizado um try/catch, e caso essa exceção seja lançada, o método retorna null, indicando que não existe um usuário com o nome de usuário e senha passados como parâmetro.
package com.devmedia.db;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import com.devmedia.model.Usuario;
public class UsuarioDAO {
private EntityManagerFactory factory = Persistence
.createEntityManagerFactory("usuarios");
private EntityManager em = factory.createEntityManager();
public Usuario getUsuario(String nomeUsuario, String senha) {
try {
Usuario usuario = (Usuario) em
.createQuery(
"SELECT u from Usuario u where u.nomeUsuario =
:name and u.senha = :senha")
.setParameter("name", nomeUsuario)
.setParameter("senha", senha).getSingleResult();
return usuario;
} catch (NoResultException e) {
return null;
}
}
public boolean inserirUsuario(Usuario usuario) {
try {
em.persist(usuario);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean deletarUsuario(Usuario usuario) {
try {
em.remove(usuario);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
Para o exemplo desenvolvido no artigo, os métodos inserir e excluir não serão utilizados, mas caso seja necessário utilizados, basta utiliza-los como o método getUsuario é chamado.
Com o acesso aos dados já implementado, é possível desenvolver o ManagedBean do JSF, que é a classe que recebe os dados que o usuário envia pela tela da aplicação, para receber os dados, é utilizado o atributo usuário, com esses dados, o método envia chama o método getUsuario da classe UsuarioDAO, caso esse método retorne null, é enviada uma tela de erro para o usuário, e ele continua na mesma página, caso contrário, o usuário é redirecionado para a tela main.xhtml. A Listagem 6 mostra o código dessa classe.
package com.devmedia.managedbeans;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import com.devmedia.db.UsuarioDAO;
import com.devmedia.model.Usuario;
@ManagedBean(name = "LoginMB")
@ViewScoped
public class LoginManagedBean {
private UsuarioDAO usuarioDAO = new UsuarioDAO();
private Usuario usuario = new Usuario();
public String envia() {
usuario = usuarioDAO.getUsuario(usuario.getNomeUsuario(), usuario.getSenha());
if (usuario == null) {
usuario = new Usuario();
FacesContext.getCurrentInstance().addMessage(
null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Usuário não encontrado!",
"Erro no Login!"));
return null;
} else {
return "/main";
}
}
public Usuario getUsuario() {
return usuario;
}
public void setUsuario(Usuario usuario) {
this.usuario = usuario;
}
}
Agora, é possível implementar a tela de login, a tela tem dois componentes de entrada, um <p:inputtext, para o usuário digitar o nome de usuário, e um <p:password, que funciona como um inputText, mas mostra os dados com o * para o usuário digitar sua senha. A Listagem 7 mostra o código do HTML desenvolvido. O componente <p:messages> é exibido caso ocorra algum erro no login, como por exemplo, se o usuário não existir.
<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="nomeUsuario" value="Nome
Usuário:" />
<p:inputText id="nomeUsuario"
value="#{LoginMB.usuario.nomeUsuario}" />
<p:outputLabel for="senha" value="Senha:" />
<p:password id="senha" value="#{LoginMB.usuario.senha}" />
<p:commandButton value="Enviar"
icon="ui-icon-star" action="#{LoginMB.envia}" ajax="false">
</p:commandButton>
</p:panelGrid>
</h:form>
</h:body>
</html>
A Figura 1 mostra a tela de login implementada, como é possível observar, existem os dois campos para o usuário digitar seu nome de usuário e a sua senha. Depois, ele pode clicar no botão Enviar, caso o login falhe, será exibida uma mensagem de erro, caso contrário, ele é redirecionado para a tela principal do sistema.
A Figura 2 mostra a tela de login no caso de um usuário ter digitado ou o nome de usuário ou a senha incorretamente, caso isso ocorra, será mostrada uma mensagem de erro.
A Listagem 8 mostra o código do XHTML da página de entrada do sistema, como o objetivo desse artigo era apenas a tela de login, essa tela exibe apenas uma mensagem dizendo “LOgin efetuado com sucesso! Bem-vindo ao sistema!”, mas seria possível implementar qualquer coisa nessa página, e o usuário só a conseguiria acessa-la via a tela de login.
<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:outputLabel value="Login efetuado com sucesso!
Bem vindo ao sistema!"></p:outputLabel>
</h:form>
</h:body>
</html>
Este artigo mostrou como configurar e implementar uma tela de login combinando os frameworks PrimeFaces, o JSF e Hibernate. A configuração feita nesse artigo serve para a criação de qualquer aplicação Web com essas tecnologias. Outro requisito que seria interessante implementar é o controle de acesso as páginas, não permitindo que usuários não logados acessem algumas páginas, mas isso é assunto para outro artigo.