quinta-feira, 11 de junho de 2009

Iniciando com JSF (Tutorial com exemplo prático)

Nesta postagem será mostrado um exemplo prático (CRUD de pessoas) para aqueles que desejam iniciar o uso da tecnologia JSF. Para isso, será utilizado o servidor de aplicação Apache Tomcat 6.0 e a IDE Eclipse Ganymede.

Para começar, é preciso criar um novo projeto. No Eclipse, basta abrir o menu file conforme mostrado na figura 1. Em seguida, será aberta uma tela para escolher o tipo de aplicação que será desenvolvida. No caso do exemplo, selecione Dynamic Web Project (figura 2) e clique no botão Next.
Na seqüência, dê um nome para o projeto (no exemplo será jsfdemo) e selecione a combo Target RunTime para Apache Tomcat v6.0 (figura 3). Depois, clique no botão Finish que o projeto estará criado.

Um vez criado o projeto, é necessário configurar o ambiente para que a aplicação funcione. Para isso, faça o download da ultima versão do JSF e extraia os jars para a pasta WEB-INF/lib do projeto. Por fim, é necessário configurar o web.xml do projeto, cuja configuração é mostrada na listagem 1.


Figura 1:Novo projeto


Figura 2: Dynamic Web Project


Figura 3: Configuração inicial do projeto


<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</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>
</web-app>
Listagem 1: web.xml

A partir deste ponto já podemos começar a efetivamente desenvolver a aplicação de exemplo.

Construindo a aplicação

Para iniciar, vamos criar os seguintes pacotes na projeto:
  • com.sample.controller;
  • com.sample.dao;
  • com.sample.model.
A figura 4 ilustra a organização dos pacotes no eclipse.

Figura 4: Pacotes

Dentro do pacote model vamos criar a classe pessoa cujo código é listado na listagem 2.

package com.sample.model;

public class Pessoa {
private Integer id;
private String nome;
private String nacionalidade;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}

public String getNacionalidade() {
return nacionalidade;
}

public void setNacionalidade(String nacionalidade) {
this.nacionalidade = nacionalidade;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Pessoa other = (Pessoa) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
Listagem 2: Pessoa.java

Dentro do pacote dao vamos definir a interface PessoaDao cujo código é mostrado na listagem 3.
package com.sample.dao;

import java.util.List;

import com.sample.model.Pessoa;

public interface PessoaDao {
void save(Pessoa pessoa);
void delete(Integer id);
Pessoa getById(Integer id);
List<Pessoa> findAll();
}
Listagem 3: PessoaDao.java

Dentro do pacote dao é necessário criar também a implementação da interface PessoaDao. No caso do exemplo será definido a classe PessoaDaoImpl (listagem 4).
package com.sample.dao;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.sample.model.Pessoa;

public class PessoaDaoImpl implements PessoaDao {
private static PessoaDaoImpl INSTANCE = new PessoaDaoImpl();
private static Map<Integer, Pessoa> database
= new HashMap<Integer, Pessoa>();
private static Integer nextId = 0;

private PessoaDaoImpl() {
}

public static PessoaDaoImpl getInstance() {
return INSTANCE;
}

@Override
public void save(Pessoa pessoa) {
if (pessoa != null) {
if (pessoa.getId() == null) {
nextId++;
pessoa.setId(nextId);
}
database.put(pessoa.getId(), pessoa);
}
}

@Override
public void delete(Integer id) {
if (id != null)
database.remove(id);
}

@Override
public Pessoa getById(Integer id) {
return database.get(id);
}

@Override
public List<Pessoa> findAll() {
return new ArrayList<Pessoa>(database.values());
}
}
Listagem 4: PessoaDaoImpl.java

Dentro do pacote controller vamos definir a classe PessoaController que será o nosso managed bean (listagem 5).
package com.sample.controller;

import java.util.List;

import javax.faces.context.FacesContext;

import com.sample.dao.PessoaDao;
import com.sample.dao.PessoaDaoImpl;
import com.sample.model.Pessoa;

public class PessoaController {
private PessoaDao pessoaDao = PessoaDaoImpl.getInstance();
private Pessoa pessoa;

public PessoaController() {
pessoa = new Pessoa();
}

public void save() {
pessoaDao.save(pessoa);
pessoa = new Pessoa();
}

public void edit() {
// pega o parametro passado no link
Integer id = Integer.parseInt((String)
FacesContext.getCurrentInstance().getExternalContext()
.getRequestParameterMap().get("id"));
pessoa = pessoaDao.getById(id);
}

public void delete(){
// pega o parametro passado no link
Integer id = Integer.parseInt((String)
FacesContext.getCurrentInstance().getExternalContext()
.getRequestParameterMap().get("id"));
pessoaDao.delete(id);
}

// getters e setters
public Pessoa getPessoa() {
return pessoa;
}

public void setPessoa(Pessoa pessoa) {
this.pessoa = pessoa;
}

public List<Pessoa> getPessoas() {
return pessoaDao.findAll();
}
}
Listagem 5: PessoaController.java

Vamos agora configurar o faces-config.xml (localizado dentro da pasta WEB-INF) cuja configuração é mostrada na listagem 6.


<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
<navigation-rule>
<from-view-id>pessoa.jsp</from-view-id>
<navigation-case>
<from-outcome>*</from-outcome>
<to-view-id>pessoa.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<managed-bean>
<managed-bean-name>pessoaController</managed-bean-name>
<managed-bean-class>
com.sample.controller.PessoaController
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
Listagem 6: faces-config.xml

Por fim, vamos criar nossa página pessoa.jsp (listagem 7).


<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<html>
<f:view>
<head>
<title><h:outputText value="Desvendando JSF" /></title>
</head>
<body>
<h:form>
<table>
<tr>
<td><h:outputText value="Nome" />:</td>
<td><h:inputText value="#{pessoaController.pessoa.nome}" /></td>
</tr>
<tr>
<td><h:outputText value="Nacionalidade" />:</td>
<td><h:inputText value="#{pessoaController.pessoa.nacionalidade}" /></td>
</tr>
<tr>
<td><h:commandButton value="salvar" action="#{pessoaController.save}" /></td>
</tr>
</table>
<h:dataTable value="#{pessoaController.pessoas}"
var="p" rendered="#{not empty pessoaController.pessoas}" border="1">
<h:column>
<f:facet name="header">
<h:outputText value="Nome" />
</f:facet>
<h:commandLink value="#{p.nome}" action="#{pessoaController.edit}">
<f:param name="id" value="#{p.id}" />
</h:commandLink>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Nacionalidade" />
</f:facet>
<h:commandLink value="#{p.nacionalidade}" action="#{pessoaController.edit}">
<f:param name="id" value="#{p.id}" />
</h:commandLink>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Excluir" />
</f:facet>
<h:commandLink value="excluir" action="#{pessoaController.delete}">
<f:param name="id" value="#{p.id}" />
</h:commandLink>
</h:column>
</h:dataTable>
</h:form>
</body>
</f:view>
</html>
Listagem 7: pessoa.jsp

A partir deste ponto, com as definições acima, podemos vizualizar a aplicação através da URL http://localhost:8080/jsfdemo/pessoa.faces .

Veja uma prévia do funcionamento dela (figura 5). Trata-se de um CRUD básico de pessoa.

Figura 5: Aplicação JSF


Um excelente referencia para quem deseja aprender conceitos relacionados ao JSF é o livro Core JavaServer Faces.

Os fontes do exemplo (incluindo Jars) estão disponíveis aqui.

Até!

Veja também:

26 comentários:

Daniel disse...

Muito bom, parabéns!

João Alves disse...

Eu também gostei!
Show de bola!

Unknown disse...
Este comentário foi removido pelo autor.
Tadeu disse...

Muito didático, parabéns!

Anônimo disse...

Post de grande ajuda.
Parabéns pela iniciativa.

Tiago disse...

Muito bom o artigo! Estou aprendendo JSF e este texto foi de grande ajuda.
Mas, tenho uma dúvida, qual a vantagem de se utilizar uma interface PessoaDao e uma classe concreta PessoaDaoImpl ao invés de apenas uma classe concreta?

Thiago disse...

Olá Tiago.
Programar para interface é uma boa prática. Talvez vc ainda não deva ter percebido sua utilidade. Tentarei de explicar.

No exemplo vc tem a interface pessoaDao com uma implementação somente (pessoaDaoImpl). Ou seja, seu uso pode ser da seguinte forma.

PessoaDao pessoaDao = new PessoaDaoImpl();

Caso amanha vc precise criar uma outra implementação do PessoaDao que salve os dados em um arquivo texto, vc so mudará uma linha de codigo.

PessoaDao pessoaDao = new PessoaDaoTextoImpl();

O resto do código será o mesmo pq as classes concretas implementam a interface pessoaDao.

Entendeu?

Tiago disse...

Opa! Vlw pela resposta Thiago, entendi sim.

Anônimo disse...

Maravilha, me ajudou muito!!!

Obrigado!

gmmascarin disse...

Galera, esse site também tem um passo-a-passo legal. http://www.arquivodecodigos.net/arquivo/tutoriais/jsf/sistema_login_usuarios.php

Anônimo disse...

Parabens Thiago, muito elaborado.
Faça tambem um tutorial JSF com JPA/Hibernate cadastrando um OneToMany

Anônimo disse...

Achei o que tava procurando , um exemplo simples mais de grande Ajuda!!

Anônimo disse...

Achei o que tava procurando , exemplo simples mais de Grande Ajuda..

André disse...

Boa noite, seguinte estou começando com jsf e estou desenvolvendo com a IDE eclipse indigo 4.0 e gostaria de saber a respeito do faces config, já olhei varios tutoriais, mas infelizmente nenhum fala a respeito do porque não gera o faces-config
e devido a este problema não estou conseguindo concluir meu projeto inicial tem como vc me dar esta ajuda.

Thiago disse...

Olá André.

O faces-config não precisa ser gerado pela IDE. Basta vc cria-lo e colocar as configurações nele. No tutorial tem um exemplo dele. Não usei nenhum plugin específico do eclipse para fazer isso.

Abraço!

Anônimo disse...

e como ficaria se eu quisesse colocar 1 botão de busca/pesquisa para pesquisar o datatable e retornar os resultados encontrados??

Anônimo disse...

Gostei muito, certamente será um grande passo para mim, gostaria de obter algum exemplo de acesso a banco de dados.

grato

sousafco@gmail.com

Thiago disse...

Olá Francisco!

Para fazer acesso ao banco, basta substituir o dao do exemplo por:

http://thiagoprocaci.blogspot.com.br/2009/04/mapeamento-objeto-relacional-com.html

Thiago disse...

Anônimo

Para filtrar os resultados no datatable vc terá que implementar um novo método no dao e no controller para isto (busca pelo nome, por exemplo, similar ao getPessoas e o findAll). Uma vez feito isso, é só colocar um botao na tela que invoque essa ação implementada.

Unknown disse...

Muito Bom Thiago... Parabéns..
Gostaria de aproveitar e matar uma curiosidade... porque para rodar temos que utilizar o caminho que voce cita... pessoa.faces?

warquia disse...

Thiago parabéns pelo artigo, sou iniciante em java, e não estou conseguindo fazer funcionar. Quando clico em Salva não acontece nada e tambem não apresenta nenhum erro. Se por gentileza teria como da um analise no meus fontes:
http://www.vivasoftware.com.br/jsfWarquia.rar

Grato.

Anônimo disse...

Parabéns e obrigado pela iniciativa, me ajudou a entender melhor.

Anônimo disse...

onde salva o arquivo .jsp?

Pentaho BI disse...

Parabéns....Belo exemplo

Anônimo disse...

Mto bom. Vlw!

Anônimo disse...

Bem interessante. Obrigado!