Além do JSF: Recursos e Práticas Incomuns para uma Matriz de

Propaganda
Décio Heinzelmann Luckow
([email protected]): é bacharel em
Sistemas de Informação pela Univille e pósgraduando em Gestão de Projetos pela
Sustentare Escola de Negócios. Já trabalhou
com as linguagens ASP, PHP, Python e tem se
especializado nas tecnologias Java, atuando
no desenvolvimento Web e integração de
sistemas. Possui as certificações Java SCJP 1.5
e SCWCD. Atua como analista de sistemas na
TOTVS, na área de Inteligência Empresarial. É
autor do livro Programação Java para a Web
da editora Novatec, além de artigos pela
revista MundoJ.
Além do JSF:
Matriz de Campos com
Recursos e Práticas Incomuns
Aprenda a construir uma tela unindo JSF e JSTL permitindo o
cruzamento de informações por meio de campos em matriz.
Este artigo ensinará como criar
formulários com campos em matriz
usando JavaServer Faces e JSTL,
utilizando recursos como eventos
de campos, validação e conversão.
Serão abordadas duas técnicas
diferentes para envio dos dados, além
de recursos interessantes e práticas
incomuns do JSF e JSTL. Estas técnicas
são importantes para ir além da
flexibilidade natural do JSF e criar telas
muito mais dinâmicas.
utilização de campos em matriz em um formulário permite a exibição e manutenção organizada de uma grande
quantidade de informações. Esta técnica é especialmente
interessante quando os dados a serem apresentados e editados
representam o cruzamento de outras informações, como, por
exemplo: valor por mês x categoria para uma planilha de orçamento. A característica fortemente dinâmica de um formulário em
matriz construído da forma como demonstraremos permite que o
montante dos dados apresentados seja alterado sem mexer na estrutura da tela construída. Para conseguir isto utilizaremos as tags
básicas do JSF funcionando em conjunto com a JSTL, eventos de
campo e um novo tipo de escopo de Managed Bean introduzido
na versão 2 do JSF. Serão demonstradas duas técnicas diferentes
para se obter os dados do formulário, sendo que a segunda técnica
utilizará um recurso de uma forma pouco explorada no JSF.
Este artigo mostrará recursos avançados do JavaServer Faces e
soluções para problemas conhecidos por desenvolvedores experientes, porém a didática do artigo permite que o leitor com pouca
experiência em JSF entenda e construa todo o exemplo proposto.
25
: : www.mundoj.com.br : :
Campos em matriz com JavaServer Faces
A criação de um formulário com matriz de campos não é algo
inédito, este pode ser criado dinamicamente em JSP ou puramente com JSTL. Porém neste artigo vamos focar na criação deste
mesmo recurso utilizando exclusivamente o JavaServer Faces e
JSTL. Isto permite que possamos contar ao mesmo tempo com as
facilidades e funcionalidades do JSF e com a organização e limpeza do código-fonte que ele provê.
Neste artigo utilizaremos como padrão a Eclipse IDE para JavaEE,
porém não existirá qualquer recurso exclusivo desta IDE, sendo
que você poderá utilizar uma diferente se preferir.
No Eclipse crie um novo Dynamic Web Project chamado matrizjsf
(consulte o quadro “Configurando o Apache Tomcat no Eclipse”
se necessário). Copie para a pasta WEB-INF\lib do projeto as bibliotecas do JSF 2 e JSTL 1.2. O JSF2 é composto pelos arquivos
jsf-api.jar e jsf-ri.jar que podem ser obtidos no endereço https://
javaserverfaces.dev.java.net/. Já o JSTL é composto pelos arquivos
jstl-api-1.2.jar e jstl-impl-1.2.jar e pode ser obtido no endereço
https://jstl.dev.java.net/download.html.
Configurando o Apache Tomcat no Eclipse
Para que se possa executar um Dynamic Web Project no
Eclipse é necessário ter um servidor web configurado. Para
isso vamos configurar o Apache Tomcat dentro do Eclipse.
Para obter o servidor web Apache Tomcat, acesse o site http://
tomcat.apache.org e faça o download o arquivo ZIP da versão
6.0, extraindo-o na sua unidade c:. No Eclipse acesse Window
> Preferences > Server > Runtime Environments. Clique em
Add e selecione Apache Tomcat 6, clique em Next; selecione
o local de instalação do Apache Tomcat e clique em Finish.
Clique com o botão direito do mouse no projeto criado (matrizjsf) e selecione Run As > Run on Server. Selecione novamente
Apache Tomcat 6, clique em Next e depois em Finish. Neste
momento o servidor Apache Tomcat já irá iniciar por dentro
do Eclipse.
Crie também uma página padrão do projeto com o nome
index.jsp na pasta WebContent. Esta poderá ter o link para a
página JSF de orçamento que criaremos em seguida, conforme
o exemplo:
<a href="orcamento.jsf">Exemplo Orçamento</a>
Para manipular o servidor posteriormente acesse a view Servers (Window > Show View > Server), clique com o botão
direito do mouse no servidor em questão e acione Start, Stop
ou Restart.
Listagem 1. Configuração do aplicativo no arquivo web.xml.
<?xml version=”1.0” encoding=”UTF-8”?>
<web-app ...>
<display-name>MundoJ</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>*.jsf</url-pattern>
</servlet-mapping>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Na classe OrcamentoBean teremos dois java.util.List categoria e
mês que serão populados no construtor com as informações que
queremos cruzar. Veja que estes dois List estão sendo populados
com a String do nome da categoria e do mês. Para saber como
guardar mais informações para cada item neste List, consulte o
quadro “Incrementando o cruzamento de informações”. Além disso, criamos um Map<String,Map<String,Float>> que preencherá
e receberá as informações do formulário, este está declarado como
um Map dentro do outro, o que garante que tenhamos duas chaves String para cada valor.
Cada campo que for gerado no formulário JSF referenciará uma
combinação de categoria e mês. Por isso que é obrigatório que
cada posição desta seja criada no Map previamente. Desta forma,
a inicialização do Map com todas as combinações possíveis é
obrigatória. Esta inicialização deve ser chamada dentro do método getValores() da classe OrcamentoBean, quando a referência
valores estiver nula, conforme a Listagem 2.
Veja que esta classe tem as anotações comuns do JSF para um
managed bean, que são @ManagedBean e @RequestScoped indicando que será criada uma nova instância desta classe para cada
requisição realizada pelo usuário.
Listagem 2. Código-fonte da classe OrcamentoBean.
A configuração necessária será no arquivo \WEB-INF\web.xml e
será apenas a configuração básica do JSF, conforme a Listagem 1.
Para exemplificar este artigo construiremos uma página de orçamento, onde será possível informar um valor para cada combinação de categoria e mês. Desta forma, o usuário poderá informar
R$ 250 para Alimentação em janeiro, R$ 500 para Educação em
julho e assim por diante. Como a página é totalmente dinâmica
você poderá exibir quantos meses e quantas categorias quiser, ou
ainda utilizar esta mesma técnica para o cruzamento de outros
tipos de informação.
26
package br.com.mundoj.web;
import java.util.*;
import javax.faces.bean.*;
@ManagedBean
@RequestScoped
public class OrcamentoBean {
private List<String> categorias = new ArrayList<String>();
private List<String> meses = new ArrayList<String>();
private Map<String,Map<String,Float>> valores;
Cont. Listagem 2. Código-fonte da classe OrcamentoBean.
public OrcamentoBean() {
this.categorias = Arrays.asList(new String[]{“Alimentação”,”Educação”
,”Transportes”,”Lazer”,”Saude”,”Impostos”});
this.meses = Arrays.asList(new String[]{“Jan”,”Fev”,”Mar”,”Abr”,”Mai
”,”Jun”,”Jul”,”Ago”,”Set”,”Out”,”Nov”,”Dez”});
}
private void inicializaValores() {
this.valores = new HashMap<String,Map<String,Float>>();
Map<String, Float> valorMes = null;
for (String cat:this.categorias) {
valorMes = new HashMap<String, Float>();
for (String mes:this.meses) {
valorMes.put(mes, new Float(0));
}
this.valores.put(cat, valorMes);
}
}
public void salvar() {
Map<String, Float> valorMes = null;
for (String cat:this.categorias) {
valorMes = this.valores.get(cat);
for (String mes:this.meses) {
System.out.println(cat+” x “+mes+” = “+valorMes.get(mes));
}
}
A página de orçamento será construída usando xhtml, que é o
formato padrão para o JSF 2. Esta página utilizará tags do JSF e
do JSTL, o que apresentará um case bastante interessante de união
destas duas tecnologias. Muito se comenta atualmente sobre o uso
dos componentes do JSF e das tags do JSTL juntos, sabe-se que o
uso do JSTL está bastante limitado em conjunto com o JSF e que
em diversos casos recomenda-se substituir a tag <c:forEach> pela
<ui:repeat> e a <c:if> pelo uso do atributo rendered dos componentes JSF, por exemplo.
Porém, esta limitação se dá pelo fato das tags do JSTL e dos componentes do JSF terem ciclos de vida diferentes, sendo que estes
são executados em momentos diferentes durante o processamento
de uma página JSF. Por isso é preciso entender bem como atua o
JSTL e JSF no processamento de uma página para saber quando
usá-los. Veja o quadro “Compatibilidade entre JSF e JSTL” para se
aprofundar nestas diferenças de ciclos de vida.
Compatibilidade entre JSF e JSTL
O JSTL nasceu há muito tempo para facilitar o desenvolvimento de páginas JSP, ele cria tags amigáveis para serem utilizadas no lugar de scriptlets contendo lógica de programação,
os famosos <%%>. O problema é que o ciclo de vida de uma
página JSP é totalmente diferente do ciclo de vida de uma página JSF. O JSP é focado em gerar HTML para ser diretamente
entregue ao navegador, já o JSF é focado em criar uma árvore
de componentes, que posteriormente serão renderizados em
formato HTML. Porém a etapa de gerar o HTML de uma página JSF (fase Render Response) é apenas a última fase do seu
ciclo de vida, antes disso ainda temos as fases:
Restore view
Apply request values
}
Process validations
public Map<String, Map<String, Float>> getValores() {
if (this.valores == null) {
this.inicializaValores();
}
return this.valores;
}
Update model values
public void setValores(Map<String, Map<String, Float>> valor) {
this.valores = valor;}
public List<String> getCategorias() {return categorias;}
public void setCategorias(List<String> categorias) {
this.categorias = categorias;}
public List<String> getMeses() {return meses;}
public void setMeses(List<String> meses) {this.meses = meses;}
}
Ainda na classe da Listagem 2, o método salvar() será referenciado
pelo botão Salvar da tela. Quando este método for chamado, o JSF
já terá preenchido o Map valores com todos os dados que estavam
em tela. A partir deste ponto, você poderá navegar por este Map
da mesma forma que fez a navegação na inicialização para obter o
valor para cada combinação de categoria e mês, conforme já está
codificado no método salvar(). A partir deste ponto você pode
fazer a persistência destas informações da forma que quiser, não
sendo este o objetivo do artigo.
Invoke application
Render response
Todas estas fases trabalham em cima de uma árvore de componentes que foi definida na página JSF (que hoje pode ser um
JSP ou XHTML).
Quando o JSP é usado juntamente com JSF ele também passa
a ter como único objetivo a montagem da árvore de componentes do JSF (para o XHTML isto é natural) e não a geração
direta do HTML como é originalmente. Por isso é que atualmente a utilização do JSTL junto ao JSF é limitado a aquelas
tags que não têm como objetivo direto a geração do HTML,
mas sim de manipular a árvore de componentes da página.
Desta forma, tags como <c:out>, <c:import>, <c:redirect> e
<c:url> não estão mais disponíveis para as páginas JSF sejam
elas usando JSP ou XHTML.
Hoje, apesar do JSF funcionar com o JSP, o formato de página
oficial é o XHTML, o JSP se mantém como opção por questões
políticas e de legado.
Na página que construiremos vamos utilizar a tag <c:forEach> em
uma situação bastante interessante e que deixará bem clara a sua
utilidade neste caso e como ela funciona. Veja na Listagem 3 como
a página ficou construída.
27
: : www.mundoj.com.br : :
Listagem 3. Código-fonte da página orcamento.xhtml.
<?xml version=”1.0” encoding=”ISO-8859-1”?>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”
xmlns:c=”http://java.sun.com/jsp/jstl/core”
xmlns:h=”http://java.sun.com/jsf/html”
xmlns:f=”http://java.sun.com/jsf/core”>
<h:head>
<title>Orçamento</title>
</h:head>
<h:body>
<h1>Orçamento</h1>
<h:form id=”orcamento”>
<h:messages />
<h:dataTable value=”#{orcamentoBean.categorias}” var=”cat”>
<h:column>
<f:facet name=”header”>Categoria</f:facet>
<h:outputText value=”#{cat}” />
</h:column>
<c:forEach var=”mes” items=”#{orcamentoBean.meses}”>
<h:column>
<f:facet name=”header”>#{mes}</f:facet>
<h:inputText
value=”#{orcamentoBean.valores[cat][mes]}”
size=”2” style=”text-align: right;”/>
</h:column>
</c:forEach>
</h:dataTable>
<h:commandButton action=”#{orcamentoBean.salvar}”
value=”Salvar” />
</h:form>
</h:body>
</html>
Podemos perceber que a <h:dataTable> irá trabalhar com as informações das categorias, ou seja, a dataTable de orçamento terá os
nomes das categorias como linhas. A primeira coluna desta tabela
terá como rótulo o texto Categoria e como valor o nome de cada
categoria declarada na classe OrcamentoBean.
As colunas seguintes desta dataTable serão formadas por cada mês
que ficou declarado na classe. Perceba que a segunda <h:column>
está envolvida em uma tag <c:forEach>, ou seja, estaremos gerando uma <h:column> para cada mês.
Neste caso, o <c:forEach> está atuando como um gerador de código-fonte JSF. Ele consegue isto pelo fato do JSTL ser executado
antes do JSF no processamento da página. É justamente por isso
que o uso do JSTL está limitado junto com o JSF. Devido a este
comportamento, você não pode utilizar tags JSTL que dependam
de valores gerados por tags JSF, pois na verdade o JSTL executa
antes do JSF. Porém, ao mesmo tempo, os managed beans do JSF
estão disponíveis para JSTL, por isto que conseguimos fazer o
<c:forEach> navegar pelos meses do orcamentoBean.
Perceba também que neste caso o uso da tag <ui:repeat> do Facelets para gerar as colunas da dataTable não seria possível, pois a tag
<ui:repeat> não será aceita como uma sub-tag da <h:dataTable>.
O caso do <c:forEach> funciona corretamente, pois na verdade o
28
JSF nem sabe da existência dele, já que o JSF só irá trabalhar com
o conteúdo que já foi previamente gerado pelo JSTL, ou seja, uma
porção de <h:columns> para os meses declarados.
Agora analisando melhor o uso do <c:forEach> e do <h:column>
no exemplo da Listagem 3 podemos perceber que a quantidade
de loops do <c:forEach> será dada pela quantidade de meses
declarados. Veja que o <c:forEach> está sendo alimentado com
a informação meses do managed bean orcamentoBean. Para definirmos o rótulo da coluna de cada mês e a indexação do Map,
utilizamos o var=”mes” definido no <c:forEach> que contém o
mês do loop atual.
O campo que exibirá e receberá os valores na tela será definido pelo componente do JSF <h:inputText>. O atributo value
deste componente apontará para a expressão #{orcamentoBean.
valores[cat][mes]}. Veja que mesmo sendo um Map e não um
array, a expressão UEL utilizada funciona como se fosse um
array e que, neste caso, está sendo indexado por valores String.
Se a propriedade valores fosse um Float[][], por exemplo, esta
expressão seria a mesma, só que teria que ser indexado por valores
numéricos.
Para testar o exemplo proposto, basta fazer o Start do servidor e
abrir a url http://localhost:8080/matrizjsf/orcamento.jsf, conforme a figura 1.
Figura 1. Tela JSF com campos em matriz.
Incrementando o cruzamento de informações
No exemplo, os java.util.List de categorias e meses são alimentados diretamente com Strings dos nomes das categorias
e dos meses. Porém, conforme a necessidade, você poderia
utilizar também objetos POJO do Java, contendo, por exemplo, número e nome do mês, e código e descrição da categoria.
Ao invés de fazer um categorias.add(“Alimentação”), faria
um categorias.add(new Categoria(1,”Alimentação”)), sendo
o mesmo para os meses. Para o caso da utilização da classe
POJO, lembre-se que é necessária a implementação dos métodos equals() e hashCode() corretamente. O Eclipse possui
recurso para gerar automaticamente estes dois métodos, para
isso acesse o menu de contexto da classe, opção Source > Generate hashcode() and equals(), depois que já tiver definido as
propriedades da classe.
Neste caso, ao exibir o nome do mês e descrição da categoria,
utilizaria as seguintes expressões respectivamente: #{mes.
nome} e #{cat.descricao}. Assim como a indexação do Map já
utilizado, ou de um Float[][] para os valores, poderia ser feito
usando números com indexadores, exemplo: #{orcamentoBean.valores[cat.codigo][mes.numero]}.
Reconhecendo os valores alterados
O exemplo construído até agora exibe e envia todos os valores
do formulário, que podem ser manipulados no método salvar().
Mas se quiséssemos receber apenas os valores que foram alterados
no formulário e não todos, como fazer? Neste caso entra um recurso bastante interessante do JSF que é o valueChangeListener.
Este permite que um método específico seja chamado somente
se o valor do campo em questão for alterado. Diferente do que a
maioria das pessoas pensa, este método somente será chamado
quando o formulário for submetido, e não quando o usuário sair
do campo em tela. Além disso, ele será chamado antes do método
que disparou a ação, neste caso o método referenciado no atributo
valueChangeListener será chamado antes do método salvar().
Para utilizar o valueChangeListener, o primeiro passo é incluir
este atributo no campo em questão, apontando para o método
que deverá se chamado, conforme a Listagem 4.
Listagem 4. Fragmento de código para utilizar o valueChangeListener.
<h:inputText
value=”#{orcamentoBean.valores[cat][mes]}”
size=”2” style=”text-align: right;”
valueChangeListener=”#{orcamentoBean.mudouValor}”/>
O método para o qual apontará o atributo valueChangeListener
deverá ter a seguinte assinatura: void meuMetodo(javax.faces.
event.ValueChangeEvent). Neste caso, este método receberá um
objeto ValueChangeEvent contendo as informações do evento
ocorrido. Dentre as informações mais interessantes podemos
destacar os métodos event.getOldValue() e event.getNewValue(),
fornecendo o antigo e o novo valor do campo, respectivamente.
O valueChangeListener funcionará em qualquer condição, porém
a informação do getOldValue() somente estará disponível se o
escopo do managed bean da tela for maior que o request, ou seja,
funcionará com os escopos @ViewScoped, @SessionScoped ou @
ApplicationScoped. Isto porque, diferente do que muitos pensam,
o “old value” não é que o valor do campo antes da tela ser exibida,
mas o valor do campo antes de receber o novo valor, quando o
formulário for submetido. Por isso que o managed bean precisa
ter um escopo maior que uma requisição, ou seja, que a instância
do managed bean não deixe de existir ao final de uma requisição.
Caso o managed bean não seja de uns dos escopos sugeridos, o
evento value change sempre será disparado, pois neste caso o old
value será sempre nulo e o new value será o valor da tela, ou seja,
valores diferentes. Por isso no caso da classe OrcamentoBean, seu
escopo deve ser alterado para @ViewScoped, que foi introduzido
na última versão do JSF. Ele tem este nome justamente porque
a instância do managed bean fica armazenada na tela (na view).
Desta forma, a instância do managed bean se manterá a mesma
enquanto a mesma tela estiver sendo exibida, o usuário pode
recarregar, submeter e reexibir a tela, que a instância continuará
existindo. Outra questão importante, mas que está restrita ao fato
de trabalharmos com informações em matriz é quanto ao valor do
campo que receberemos no evento value change. O fato de sabermos qual o “new value” do campo alterado não nos diz de qual
categoria e de qual mês este valor veio. Como podemos resolver
esta questão?
Neste momento entra como sugestão um uso incomum para uma
tag do JSF, que é a tag <f:attribute>. Desta forma, criaremos nossos
próprios atributos para os campos da matriz, e recuperando-os na
ocorrência do evento. Veja na Listagem 5 como ficará a definição
do campo utilizando este recurso.
Listagem 5. Uso customizado da tag <f:attribute>.
<h:inputText
value=”#{orcamentoBean.valores[cat][mes]}”
size=”2” style=”text-align: right;”
valueChangeListener=”#{orcamentoBean.mudouValor}”>
<f:attribute name=”cat” value=”#{cat}”/>
<f:attribute name=”mes” value=”#{mes}”/>
</h:inputText>
Mesmo que os atributos cat e mes não sejam oficiais do JSF, ele
aceita que estes sejam definidos. Veja na Listagem 6 como ficará
definido o método mudouValor() na classe OrcamentoBean, e a
recuperação dos atributos customizados.
Listagem 6. Método mudouValor da classe OrcamentoBean.
public void mudouValor(ValueChangeEvent event) {
String cat = (String) event.getComponent().getAttributes().get(“cat”);
String mes = (String) event.getComponent().getAttributes().get(“mes”);
Float _old = (Float) event.getOldValue();
Float _new = (Float) event.getNewValue();
System.out.println(cat+” x “+mes+” de: “+ _old + “ para: “ + _new);
}
Validação
Listagem 7. Identificação do campo para validação.
<h:inputText
value=”#{orcamentoBean.valores[cat][mes]}”
size=”2” style=”text-align: right;”
label=”Valor para #{cat} em #{mes}”
required=”true”
valueChangeListener=”#{orcamentoBean.mudouValor}”>
<f:attribute name=”cat” value=”#{cat}”/>
<f:attribute name=”mes” value=”#{mes}”/>
</h:inputText>
Uma questão importante, caso seja necessário algum tipo de validação para os campos em matriz é como identificar o campo que não
passou na validação. O componente <h:inputText>, assim como os
outros campos de formulário, possuem o atributo label. Este atributo é
a identificação do campo para as mensagens de validação. Para o caso
de matriz de campos é interessante identificar no label o cruzamento
das informações. Na Listagem 7 exibimos a configuração deste campo
para que seja facilmente identificável em uma mensagem de validação.
Utilizando uma validação básica como o required=”true” e o atributo
label, ao submeter o formulário com algum campo em branco a seguinte mensagem será apresentada.
Valor para Alimentação em Fev: Erro de validação: o valor é necessário.
29
: : www.mundoj.com.br : :
Formatação e conversão
Listagem 8. Conversor customizado para campo Float em
matriz.
package br.com.mundoj.web;
import java.text.NumberFormat;
import java.text.ParseException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;
@FacesConverter(value = “mundoj.DecimalConverter”)
public class DecimalConverter implements Converter {
private NumberFormat
nf;
public DecimalConverter() {
this.nf = NumberFormat.getNumberInstance();
this.nf.setMinimumFractionDigits(2);
this.nf.setMaximumFractionDigits(2);
}
@Override
public Object getAsObject(FacesContext context,
UIComponent component, String value) {
try {
return new Float(nf.parse(value).floatValue());
} catch (ParseException e) {
throw new ConverterException(e.getMessage());
}
}
@Override
public String getAsString(FacesContext context,
UIComponent component, Object value) {
return nf.format(value);
}
}
Como você deve ter percebido, os valores que estão sendo apresentados no formulário estão no formato padrão do Java 0.0 e não 0,00
como seriam de se esperar para informação monetária no Brasil. Para
uma questão como essa a primeira solução que vem a mente é utilizar
a tag <f:numberFormat> que tem justamente como objetivo a formatação nesta situação. Porém, talvez por um comportamento padrão
do JSF ou a forma altamente dinâmica na qual este exemplo foi construído, somente neste caso o JSF não respeita o tipo Float de destino
quando utilizamos o <f:numberFormat>. Como consequência, se for
digitado um valor “25” ele entenderá como um Long, se for digitado
um valor 25,5 ele entenderá como um Float. Da mesma forma, os
campos que forem mantidos como 0,00 terão o seu old value como
Float e o seu new value como Long. Isto faz com que o JSF ache que
todos os campos do formulário sofreram alteração, pois o tipo do old
value está diferente do new value, mesmo que o valor nominal seja o
mesmo. Assim, para todos os campos o método mudouValor() será
acionado, mesmo que o valor não tenha sido alterado. Neste caso,
qual seria a forma correta de se formatar o valor do campo sem que
30
estes problemas ocorram? A solução é criar um conversor customizado que force a conversão para o tipo Float, o que no JSF pode ser feito
em algumas linhas de código, conforme a Listagem 8.
Nesta classe, a annotation @FacesConverter se encarrega de nomear
este conversor como mundoj.DecimalConverter. Este nome deve ser
utilizado ao configurar o <h:inputText> da tela, informando o atributo converter=”mundoj.DecimalConverter”.
Livro Programação Java para a Web
Este artigo apresentou não apenas a criação de um formulário em matriz usando o
JSF, mas também diversos outros recursos
que podem ser aplicados de diversas formas aos seus projetos. A criação de uma
página de orçamento para este objetivo
segue a ideia de ensinar a tecnologia por
meio de exemplos úteis e interessantes.
Esta abordagem de utilizar exemplos
interessantes para ensinar Java também é
adotada pelo livro Programação Java para
a Web da editora Novatec (www.javaparaweb.com.br). Este livro possui uma temática inovadora, com
enfoque extremamente prático, que mostra passo a passo como
desenvolver uma aplicação web utilizando a linguagem Java e as
tecnologias mais poderosas e populares no arsenal dos desenvolvedores, como JavaServer Faces e Hibernate.O método utilizado
no livro se baseia no projeto de uma aplicação financeira pessoal,
em que são abordadas várias técnicas de desenvolvimento em
cada etapa do projeto, desde as mais tradicionais e conhecidas até
as mais modernas e avançadas.
O artigo apresenta recursos que podem complementar seus
próprios projetos e o projeto abordado no livro, tornando-os
ainda mais interessantes. Além disso, o livro também aborda os
requisitos básicos de um sistema construído de forma profissional em Java, como: JavaServer Faces, Hibernate, Facelets, CSS,
Spring Security, Ajax, PrimeFaces, internacionalização, iReport e
Jasper Reports, JfreeChart, WebServices e busca de informações
em meios externos.
Considerações finais
Este artigo mostrou de forma prática a construção de uma tela em
JavaServer Faces que exibe e edita informações em matriz. Utilizou
recursos como união do JSF e JSTL, @RequestScoped e @ViewScoped, ValueChangeListener, validação e conversão/formatação de
valores. Porém, mais do que isso, mostrou diversas técnicas interessantes e incomuns no desenvolvimento JSF e que poderão ser
reaproveitadas pelo leitor em contextos diferentes do apresentado•
Referências
• Livro Programação Java para a Web; Luckow, Décio Heinzelmann; Melo,
Alexandre Altair de. Editora Novatec. 2010.
• Java EE Tutorial.
http://download.oracle.com/javaee/5/tutorial/doc/.
• Site do JSF:
https://javaserverfaces.dev.java.net
• Site do JSTL:
https://jstl.dev.java.net
• Site do Apache Tomcat:
http://tomcat.apache.org
• Site do Eclipse:
http://www.eclipse.org/
Download