Esse artigo faz parte da revista Java Magazine edição 23. Clique aqui para ler todos os artigos desta edição

imagem

Atenção: por essa edição ser muito antiga não há arquivo PDF para download.Os artigos dessa edição estão disponíveis somente através do formato HTML. 

JSF Customizado

Componentes e Extensões na Prática

 

Ajuste o JSF para as necessidades das suas aplicações, criando validadores, conversores, componentes de interface e renderizadores

 

Os frameworks web têm se tornado fundamentais no desenvolvi­mento de aplicações J2EE, sendo em muitas aplicações tão importantes quanto a própria JVM ou os containers web. Mas é claro que não há como prever todas as necessidades das aplicações que irão usar um framework. A orientação a objetos e os padrões de projeto permi­tem personalizar o comportamento das classes, mesmo sem acesso ao seu código fonte. Mas além desses recursos, um bom framework deve fornecer mecanismos de extensão claros, que facilitem a adaptação para as necessidades particulares de cada sistema.

 

A capacidade de extensão do JSF é um dos pontos notáveis da especificação. a JSF é totalmente customizável, sendo pos­sível criar novos componentes de interface (visuais ou não), alterar o comportamento de componentes existentes ou até mesmo intervir no fluxo de tratamento de requisi­ções. E a maioria das extensões são simples de desenvolver.

O objetivo deste artigo é apresentar o desenvolvimento de componentes customizados para o JSF, e mostrar que isso não é uma habilidade secreta de gurus de Java, mas uma prática comum e de grande valor no cotidiano do desenvolvimento para web. Serão abordados os tipos extensões do JSF: Validators, Converters, UI Components e Renderers. Para acompa­nhar os exemplos, você vai precisar conhe­cer o básico do JSF (consulte por exemplo o artigo "JSF na prática" da Edição 22).

 

Quando criar um componente?

O JSF simplifica o desenvolvimento de componentes, mas você pode poupar muito esforço apenas verificando se um novo componente é realmente necessário, e se é possível atender às necessidades da aplicação com componentes disponíveis. A primeira tarefa é definir exatamente o que precisa ser feito.

 

Validadores

 

Se queremos filtrar a entrada de dados do usuário, principalmente em campos digitados, um Validator (validador) deve ser utilizado. Pela especificação do JSF, sempre contamos com validadores para faixas de valores de double/Double, long/Long e para o tamanho de strings1. Implemen­tações específicas podem oferecer outros validadores. Por exemplo, o MyFaces (a principal implementação open source do JSF) inclui valida dores para endereços de e-mail, números de cartão de crédito e expres­sões regulares, entre outros.

Para atender a regras de vali­dação específicas da aplicação, pode ser desenvolvido um validador customizado. Neste artigo vamos criar um validador de números de cartão de crédito que faz a verificação em um cadastro.

 

Conversores

Se o objetivo é converter dados fornecidos pelo usuário para outros tipos, devemos usar um Converter (conversor). É o caso, por exemplo, se precisarmos transformar uma data digitada (uma string) em um java.util.Date ou um java.util.Date numa string formatada. A especificação do JSF garante a presença de conversores de/para BigDecimal, Biglnteger, Boolean, Byte, Character, DateTime, Double, Float, Integer, Long, Number e Short.

Usaremos um conversor para transformar o número de um cartão (também uma string) em sua representação no modelo (jsf2.CartaoDeCredito) e vice versa.

 

Componentes de Interface

Se precisamos usar uma funcionalidade do HTML ainda não existente nos componentes (ex.: layers arrastáveis), criar um novo tipo de componente (como uma barra de progresso), ou introduzir grandes mudanças em componentes gráficos existentes, então será necessário um novo UI Component (componente de interface).

Antes de iniciar o desenvolvimento de um componente de interface, no entanto, não deixe de analisar os existentes. O MyFaces, por exemplo fornece componentes customizados para menus de navegação, tabelas de dados com ordenação, calendários e upload de arquivos, e mais. O Oracle ADF Faces é outra opção, que, além de vários componentes úteis, inclui recursos como o escopo "page flow" (que simplifica a passagem de objetos entre páginas).

Neste artigo vamos desenvolver um componente de interface para a escolha de datas (mostrado em execução na Figura 1).

 

 imagem

 

 

 Figura 1. Componentes desenvolvidos no artigo

 

Renderizadores

Para exibir um componente de interface em outro dispositivo ou numa linguagem diferente de HTML (ex.: WML ou XML), ou para adicionar a ele novas caracterÍsticas de apresentação, podemos criar um novo Renderer (renderizador).

Como exemplo, vamos criar um renderizador para mostrar uma imagem "rollover", trocada dinamicamente.

 

Criando validadores

O tipo mais simples de validador consiste num método no backing bean que verifica o valor submetido. Nesse caso, não são necessárias mudanças no faces-config.xml.

A assinatura do método de validação deve ser como a seguinte:

 

public void validarCartaoDeCredito (FacesContext fc,

  UlComponent uic, Object value) throws ValidatorException;

 

Aqui o objeto do tipo FacesContext representa o ambiente JSF associado ao request atual. Através dele, podemos obter a árvore de componentes (javax.faces.component.UIViewRoot), adicionar mensagens, modificar, concluir ou abortar a requisição HTTP e acessar o contexto externo ao JSF (que é comumente um ServletContext ou PortletContext).

Através de um FacesContext podemos também obter uma referência a um objeto do tipo javax.faces.application.Application, que representa a aplicação e dá acesso aos objetos ResourceBundle e Locale, para internacionalização. O objeto Application oferece algumas facilidades fundamentais, como a instanciação de componentes, e a criação e avaliação de vínculos.

 

Vínculos são objetos que associam expressões (como #{meuBean.propriedade}), com as propriedades correspondentes dos objetos gerenciados no lado do servidor. Há objetos de vínculo para expressões associadas a métodos (MethodBinding).

 

Finalmente, os demais parâmetros do método são o componente (uic) e o valor (value), que estão sendo verificados no processo de validação.

Para indicar o método criado como validador de um componente, devemos referenciá-lo no atributo validator. Por exemplo:

 

<h:inputText validator=

      "#{backingBeanQualquer.validarCartaoDeCredito}"

       value=" #{ backingBeanQualquer.numeroDoCartao)"

       required = "true" id = "cartaoDeCredito" >

</h:inputText>

 

Note que tornamos o campo obrigatório fazendo required="true".

Tendo definido e associado o validador ao componente, todas as vezes que o componente for avaliado, será invocado o método de validação. Se uma ValidatorException for lançada, o componente será considerado inválido e a view à qual pertence é retomada ao cliente, permitindo a correção.

 

A avaliação só será invocada se houver um valor digitado a ser validado; ela não é disparada se nada for digitado no campo.

 

Um problema com essa abordagem, entretanto, é que ela limita a reusabi­lidade. Se o método de validação fosse necessário em diversos beans, ele preci­saria ser copiado ou extraído para uma superclasse comum, ou ainda delegado a outro objeto.

Para contornar o problema você pode criar uma classe separada com o validador:

1. Crie uma nova classe que implemente a interface javax.faces.validator.Validator. Há apenas um método a ser implementado, análogo ao mostrado anteriormente:

 

public void validate (FacesContext fc,

   UIComponent uic,Object valor) thows ValidatorExcepion;

 

2.Registre o validator no faces-config.xml:

 

<validator>

<validator-id>jm.CartaoDeCreditoValidator </validator-id>

<validator-class>jsf2.CartaoDeCreditoValidator </validator-class>

</validator>

 

  

3. Adicione o validator ao componente com o id registrado no faces-config.xml:

 

<h:inputText

     value=”#{backingBeanQualquer.numeroDoCartao}”

     required = “true” id=”cartaoDeCredito”>

<f:validator validatorld=”jm.CartaoDeCreditoValidator”/>

</h:inputText>

 

O código completo após realizar esses passos está na Listagem 1, onde foram omitidos trechos não relevantes ao exem­plo, como a verificação de tipos (o código completo pode ser obtido no site da Java Magazine).

No exemplo, apenas verificamos se o número do cartão pertence ao ca­dastro do sistema, usando o método CartaoDeCredito.buscarCartao(). Verificações adicionais (pela data de validade do cartão, por exemplo) poderiam ser acrescentadas de forma semelhante.

Mas esta abordagem pode ainda não ser suficiente: pode ser necessário parametrizar o validador com atribu­tos novos, ausentes na tag <f:validator>, como por exemplo a bandeira do cartão. Vamos criar uma tag customizada com es­ses atributos: <jm:validador CartaoDeCreditoBandeira>. Primeiro estendemos estendemos a classe base javax.faces.webapp.ValidatorTag do JSF para tags de validação. Depois criamos a definição da tag na tag library e usamos a tag no JSP, como mostrado na Listagem 2 (jm.tld). A tela resultante, com as validações de acordo com a bandeira, será semelhante à mostrada na Figura 2.

 

Em aplicações reais, é recomendável que método javax.faces.validator.Validator.validate() delegue para outro método a lógica de validação em si, desvinculando essa lógica do contexto e do componente JSF. Isso facilita a manutenção do código e a criação de testes unitários. Além do mais, os algoritmos dos validadores customizados dentro de uma aplicação costumam ser muito parecidos, o que sugere o uso do padrão de projeto “Template Method” (veja meu artigo “Mais Patterns aplicados”, na Edição 21).

 

 

 imagem

 

 Figura2. Validador com bandeira

 

Listagem 1. Validador__________________________________________________

 

CartaoDeCreditoValidator.Java                                                                                    

 

public class CartaoDeCreditoValidator implements Validator {

     public static final String VALIDATOR_ID = “jm.CartaoDeCreditoValidator”;

    

    Public void validate(FacesContext fc, UIComponent uic,

          Object value) throws Validator Exception ...

Quer ler esse conteúdo completo? Tenha acesso completo