Arquivo de December 2007

Foi liberado ontem (17/12/2007) mais uma nova versão do conjunto de componentes para JSF conhecido como JBoss RichFaces. Nesta nova versão foram corrigidos dezenas de bugs, aperfeiçoados alguns componentes, atualizados os frameworks Prototype e script.aculo.us(para 1.6.0 e 1.8.0 respectivamente), além da adição de 4 novos componentes: Ordering List, List Shuttle, Component Control e Context Menu. Para mais informações sobre as novidades desta versão leia o WhatsNew. Faça download dos fontes, binários e documentação na página oficinal.

Comments Nenhum comentário »


Introdução

Dando continuidade ao meu último POST, estarei apresentando uma maneira simples de trabalhar com Ajax utilizando componentes JSF.
As aplicações que usufruem de recursos Ajax têm evoluído de diversas maneiras nos últimos tempos e um dos aspectos importantes é a produtividade. Quando iniciei os meus estudos sobre Ajax, era necessário escrever uma quantidade significativa de código javascript, manipulando o objeto XmlHttpRequest diretamente, além de uma porção adicional de código em alguma linguagem server side (para gerar XML dinamicamente). Depois de um certo tempo vieram os frameworks javascript que diminuiram a quantidade de código a ser escrito e atualmente é possível desenvolver aplicações inteiras sem utilizar nenhum código javascript, através dos componentes do RichFaces (entre outros).

Requisitos

Antes de seguir os passos aqui descritos, é recomendável que você leia o POST Java Server Faces 1.2 Hello World ou tenha conhecimentos compatíveis.

Configurando o ambiente

Para rodar aplicações Java Server Faces 1.2 é necessário um container que implemente a especificação da JSP 2.1. Para este tutorial iremos utilizar o container Tomcat 6.0.
Download:
http://tomcat.apache.org/download-60.cgi

Além dos jars para rodar o Java Server Faces 1.2 serão necessários mais 3 jars do RichFaces. Quando este POST foi escrito a versão mais recente do RichFaces era a 3.1.2. Desta forma, os nomes dos jars são: richfaces-api-3.1.2.GA.jar, richfaces-impl-3.1.2.GA.jar e richfaces-ui-3.1.2.GA.jar e se encontram dentro da pasta lib do arquivo disponível para download.
Download: http://labs.jboss.com/jbossrichfaces/downloads/

Para configurar o RichFaces serão necessárias algumas pequenas modificações no web.xml demonstrado no POST Java Server Faces 1.2 Hello World. A listagem 1 apresenta o código completo do novo web.xml.

Listagem 1

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
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/webapp_2_5.xsd">
<display-name>JSFAjax</display-name>

	<context-param>
		<param-name>com.sun.faces.verifyObjects</param-name>
		<param-value>true</param-value>
	</context-param>

	<context-param>
		<param-name>com.sun.faces.validateXml</param-name>
		<param-value>true</param-value>
	</context-param>

	<context-param>
		<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
		<param-value>clien+t</param-value>
	</context-param>

	<context-param>
		<param-name>org.richfaces.SKIN</param-name>
		<param-value>blueSky</param-value>
	</context-param>

	<filter>
		<display-name>RichFaces Filter</display-name>
		<filter-name>richfaces</filter-name>
		<filter-class>org.ajax4jsf.Filter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>richfaces</filter-name>
		<servlet-name>Faces Servlet</servlet-name>
		<dispatcher>REQUEST</dispatcher>
		<dispatcher>FORWARD</dispatcher>
		<dispatcher>INCLUDE</dispatcher>
	</filter-mapping>

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

	<welcome-file-list>
		<welcome-file>faces/index.jsp</welcome-file>
	</welcome-file-list>

</web-app>

Um novo parâmetro de contexto foi adicionado para configurar qual skin o RichFaces irá utilizar. Por padrão, podem ser utilizados 8 valores: DEFAULT, plain, emeraldTown, blueSky, wine, japanCherry, ruby, classic e deepMarine. É possível criar novas skins e modificar os estilos dos componentes através de CSS, entretanto, este assunto será abordado em uma outra oportunidade.
Para utilizar o restante dos recursos do RichFaces o filtro org.ajax4jsf.Filter deverá ser configurado. Existem algumas opções de configuração e até diferentes tipos de configurações para um grupo de páginas. Para maiores detalhes sobre configurações dos filtros do RichFaces utilize a seção 5.5 - Filter Configuration da documentação.

Criando o javabean

Utilizaremos um simples javabean para efetuarmos um CRUD. Na listagem 2 será apresentado a classe Contato.java que deverá ser criada no pacote br.com.jsfajax.entity.

Listagem 2

package br.com.jsfajax.entity;

import java.util.Date;

public class Contato {

	private String nome;
	private Date dataNascimento;
	private String email;

	public String getNome() {
		return nome;
	}

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

	public Date getDataNascimento() {
		return dataNascimento;
	}

	public void setDataNascimento(Date dataNascimento) {
		this.dataNascimento = dataNascimento;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

}


Criando o Bean Gerenciado (Managed Bean ou Backing Bean)

Crie no pacote br.com.jsfajax.web.mbean o arquivo ContatoManager.java conforme demostra a listagem 3.

Listagem 3

package br.com.jsfajax.web.mbean;

import br.com.jsfajax.entity.Contato;

import java.util.ArrayList;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;

public class ContatoManager {

	private Contato contato;
	private List<Contato> contatos;
	private DataModel contatosData;

	public ContatoManager() {

		contato = new Contato();
		contatos = new ArrayList<Contato>();
		contatosData = new ListDataModel(contatos);

	}

	public Contato getContato() {
		return contato;
	}

	public void setContato(Contato contato) {
		this.contato = contato;
	}

	public List<Contato> getContatos() {
		return contatos;
	}

	public void setContatos(List<Contato> contatos) {
		this.contatos = contatos;
	}

	public DataModel getContatosData() {
		return contatosData;
	}

	public void setContatosData(DataModel contatosData) {
		this.contatosData = contatosData;
	}

	public void salvar(ActionEvent e) {

		// Se o contato já existia antes na lista de contatos, atualiza os dados. Do contrário adiciona.
		if(contatos.contains(contato))
			contatos.set(contatos.lastIndexOf(contato), contato);
		else
			contatos.add(contato);

		// Zera o contato para que os campos do formulário sejam limpos.
		contato = new Contato();

		// Cria uma nova mensagem de informação para o JSF
		FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
							"Contato adicionado com sucesso!",
							"Contato adicionado com sucesso!");

		// Adiciona a mensagem ao formulário de cadastro
		FacesContext.getCurrentInstance().addMessage("formularioCadastro", message);

	}

	public void deletar(ActionEvent e) {
		contatos.remove((Contato)contatosData.getRowData());
	}

	public void editar(ActionEvent e) {
		contato = (Contato)contatosData.getRowData();
	}

	public boolean isRendered() {
		return !contatos.isEmpty();
	}

}


Configurando o Bean Gerenciado no faces-config.xml

Adicione ao faces-config.xml o código conforme demonstra a listagem 4:

Listagem 4

<managed-bean>
	<managed-bean-name>contatoManager</managed-bean-name>
	<managed-bean-class>br.com.jsfajax.web.mbean.ContatoManager</managed-bean-class>
	<managed-bean-scope>session</managed-bean-scope>
</managed-bean>


Criando a página JSP

Crie um arquivo chamado index.jsp, no diretório WEB-INF/ de sua aplicação WEB, com o conteúdo demonstrado na listagem 5.

Listagem 5

<%@ taglib uri="http://richfaces.org/a4j" prefix="a4j"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://richfaces.org/rich" prefix="rich"%>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
		<title>Contato CRUD</title>
	</head>
	<body>
	<f:view>
          <h:form id="formularioCadastro">
         	<rich:panel id="cadastro" header="Cadastro de Contatos">
         		Nome:
         		<h:inputText value="#{contatoManager.contato.nome}" id="nome" required="true"
				requiredMessage="Digite o nome corretamente!"/> <br />
         		Data Nascimento (dd/mm/aaaaa):
         		<h:inputText value="#{contatoManager.contato.dataNascimento}" id="dataNascimento"
				required="true" requiredMessage="Digite a data de nascimento!"
				converterMessage="Digite a data de nascimento no formato correto!">
         			<f:convertDateTime pattern="dd/MM/yyyy"  />
         		</h:inputText> <br />
         		E-mail:
			<h:inputText value="#{contatoManager.contato.email}" id="email" required="true"
				requiredMessage="Digite o e-mail corretamente!"/> <br />
         		<a4j:commandButton value="Salvar"  actionListener="#{contatoManager.salvar}"
				reRender="cadastro,formularioLista" /><br /><br />
         		<h:messages errorStyle="color:red" infoStyle="color:#5ac67e"  />
         	</rich:panel>
           </h:form>
           <h:form id="formularioLista">
           	<rich:dataTable value="#{contatoManager.contatosData}" var="contato"
			id="listaContatos" rendered="#{contatoManager.rendered}">
           		<h:column>
				<f:facet name="header">
					<h:outputText value="Nome" />
				</f:facet>
				<h:outputText value="#{contato.nome}"/>
			</h:column>
			<h:column>
				<f:facet name="header">
					<h:outputText value="Data Nascimento" />
				</f:facet>
				<h:outputText value="#{contato.dataNascimento}">
					<f:convertDateTime pattern="dd/MM/yyyy"/>
				</h:outputText>
			</h:column>
			<h:column>
				<f:facet name="header">
					<h:outputText value="E-mail" />
				</f:facet>
				<h:outputText value="#{contato.email}"/>
			</h:column>
			<h:column>
				<f:facet name="header">
					<h:outputText value="Editar" />
				</f:facet>
				<a4j:commandLink value="Editar"
					actionListener="#{contatoManager.editar}" reRender="cadastro"/>
			</h:column>
			<h:column>
				<f:facet name="header">
					<h:outputText value="Deletar" />
				</f:facet>
				<a4j:commandLink value="Deletar"
					actionListener="#{contatoManager.deletar}" reRender="listaContatos"/>
			</h:column>
           	</rich:dataTable>
           </h:form>
        </f:view>
     	</body>
</html>

Conforme demonstrado na listagem 5, serão utilizadas mais duas taglibs responsáveis pelas funcionalidades Ajax, http://richfaces.org/a4j representada pelo apelido a4j e http://richfaces.org/rich representada pelo apelido rich.
Foram utilizados 2 formulários pois todo formulário com campos cujo atributo required possua o valor true só pode ser submetido se tais campos estiverem preenchidos. Desta forma, se os botões de editar e deletar (quando em um mesmo form) forem acionados e os campos (com required=true) estiverem vazios uma mensagem de erro será apresentada.
O atributo requiredMessage do componente h:inputText é utilizado para configurar a mensagem de erro a ser apresentada quando este campo não for preenchido e seu atributo required possuir o valor true.
O converter f:converterDateTime é utilizado para transformar a String digitada (no campo em que este converter for aplicado) em um objeto do tipo java.util.Date e vice-versa.
O atributo converterMessage do componente h:inputText é utilizado para configurar a mensagem de erro a ser apresentada quando não for possível efetuar a conversão da String para o objeto java.util.Date ou vice-versa.
Os componentes commandButton e commandLink do a4j serão responsáveis por efetuar as chamadas assíncronas. No atributo actionListener destes componentes é configurado qual método do managed bean será executado. No atributo reRender será configurado quais componentes serão atualizados depois de ser executado o método do managed bean. Desta forma, quando o botão salvar for pressionado o método salvar do managed bean será executado e o componente cujo ID é listaContatos será atualizado com um novo registro.
O componente h:messages é reponsável por apresentar as mensagens adicionadas ao FacesContext através da classe FacesMessage.
É possível customizar os estilos CSS das mensagens em função do tipo de mensagem. Um FacesMessage pode ser classificada em 4 tipos:

  • FacesMessage.SEVERITY_ERROR - Indica que um erro ocorreu.
  • FacesMessage.SEVERITY_FATAL - Indica que um erro grave ocorreu.
  • FacesMessage.SEVERITY_INFO - Mensagem com caráter informativo.
  • FacesMessage.SEVERITY_WARN - Indica que um erro pode ter acontecido.

Para utilizar estilos de CSS diferente para cada tipo de mensagem existem atributos correspondentes no componente h:messages, são eles: errorClass, fatalClass, infoClass, warnClass, errorStyle, fatalStyle, infoStyle e warnStyle. Estes atributos são correspondentes aos atributos style e class dos componentes html.

Considerações Finais

Através da utilização de componentes JSF é possível ganhar produtividade, diminuindo a quantidade de código e, na maioria das vezes, ganhar performance. Entretanto, em muitas situações isto não ocorre, devido a grande quantidade de chamadas assíncronas, consultas à base de dados desnecessárias, utilização indevida de session entre outros fatores. Em uma próxima oportunidade darei continuidade a este POST adicionando recursos da Java Persistence API e mostrando como otimizar o desempenho desta pequena aplicação.

Comments Nenhum comentário »