Utilizando AJAX com JSF de maneira eficiente

Graças a natureza orientada à componentes e eventos do JavaServer Faces podemos implementar aplicações com AJAX de maneira simples e prática. Existem vários frameworks e conjuntos de componentes AJAX disponíveis para JSF, uns mais simples e super fáceis de integrar, outros mais chatinhos, porém bastante eficientes em determinados cenários. Entre eles o mais utilizado e prático sem dúvida nenhuma é o Ajax4jsf que é trazido juntamente com o conjunto de componentes Richfaces da JBoss, com ele é possível inserir recursos AJAX em aplicações JSF de forma transparente e bastante produtiva.

Mesmo com a toda a simplicidade e gama enorme de componentes/frameworks AJAX ainda assim estes recursos não são aproveitados de forma eficiente ao se desenvolver com JSF, muitos desenvolvedores mesmo utilizando-se destes recursos continuam pensando de forma “click’n’wait”, o que no final das contas acaba meio que “anulando” os benefícios oferecidos por tais recursos.

Na onda de aplicações ricas e WEB2.0 não podemos deixar de aproveitar certos recursos essenciais para desenvolver tais aplicações. Utilizar estes recursos em JSF de forma eficiente trará ganhos consideráveis em vários aspectos para o projeto, à equipe de desenvolvimento e principalmente ao cliente, entre eles podemos destacar aspectos como performance, escalabilidade, produtividade e principalmente usabilidade.

Mas fica a pergunta: Como conseguir isso?

Abandonando a velha escola

O que precisamos fazer é deixar de lado o pensamento em interfaces “click’n'wait”, deixar de lado o desenvolvimento baseado em “action-like”, abandonar a navegação dirigida à páginas, precisamos aproveitar melhor os recursos AJAX oferecidos por frameworks e componentes ricos, inserir maior usabilidade nas páginas, aprender um pouco sobre AJAX Patterns e obter mais produtividade ao desenvolver páginas com JSF.

Com estes pensamentos em mente já temos uma melhor direção para um desenvolvimento mais eficiente. Para obter isso eu pretendo me utilizar de certas premissas básicas, como:

  • Utilizar um conjunto de componentes ricos e um framework AJAX. (Neste caso eu optei pelo Richfaces/Ajax4jsf por ser bastante simples de usar e integrar, por ser estável e por ser bastante utilizado na comunidade, contudo, qualquer outro conjunto de componentes AJAX poderia ser utilizado, como Trinidad ou mesmo o IceFaces);
  • Desenvolver as regras de navegação entre views orientada à estados e não à páginas;
  • Inserir um maior controle de fluxo de navegação e inteligência nos managed beans;
  • Utilizar algum framework de templating. (Optei pelo Facelets por ser simples, prático, produtivo, estável, ter uma excelente performance e principalmente por ter sido desenvolvido para JSF);
  • Diminuir o número de páginas (xhtml, jspx, jsp etc) no projeto;
  • Evitar reloads/refresh de páginas ao máximo, ou sempre que possível;

Observando a lista acima fica fácil ver que a maioria dos itens se complementam e colaboram entre si, porém o mais importante sem dúvida é o 2º item, “Desenvolver as regras de navegação entre views orientada à estados e não à páginas”, acho que este item resume 90% do que pretendo falar. Baseado nestas premissas básicas vou implementar uma aplicação bem simples (CRUD) e comentar certos pontos nela que facilitarão o entendimento.

Desenvolvendo as regras de navegação orientada à estados

Primeiramente devemos tirar da cabeça a maneira convencional de criar as regras de navegação orientada à páginas, ou seja, ter que desenvolver 3 ou 4 páginas para implementar um CRUD por exemplo, páginas como searchlist.jsp, add.jsp, update.jsp e show.jsp (algumas vezes se resume em até 2 páginas) devem ser descartadas. Ter várias páginas significa neste caso ter várias árvores de componentes, significa que o framework precisa gerar novas árvores de componentes a cada mudança de página, e isso custa memória e processamento no servidor, sem falar consumo de banda e overhead no cliente (browser).

Sendo, substituiremos essa abordagem da velha escola por outra mais eficiente, orientada à estados, em que utilizaremos somente uma única página que terá seu fluxo de navegação gerenciado por um managed bean mais inteligente.

A idéia principal tem por objetivo evitar escrever muitas páginas para representar cada view (tela), diminuindo assim o número de páginas no projeto, o número de regras de navegação no faces-config.xml, diminuindo o overhead no servidor e no cliente a cada refresh de página, obtendo uma melhor performance utilizando sempre a mesma árvore de componentes, inserir maior usabilidade na aplicação para o usuário, e claro, aproveitar eficientemente os recursos AJAX em cada página.

Logo, eu criei um template bem simples com Facelets para nossas páginas de CRUDs, com este template dá para ter uma idéia de como poderíamos escrever páginas bem melhores para nossas aplicações, o template (parte dele) seria algo do tipo:

[myCrudTemplate.xhtml]

<body>
	<a4j:outputPanel ajaxRendered="true" id="mainOutputPanel">
		<a4j:form>
			<!-- bloco de pesquisa -->
			<rich:panel id="searchlistBlock"
						rendered="#{defaultBean.pesquisarState}">
				<f:facet name="header">
					Pesquisar
		        </f:facet>
				<ui:insert name="searchlistBlock">
				</ui:insert>
			</rich:panel>
			<!-- bloco de edição -->
			<rich:panel id="addUpdateBlock"
						rendered="#{defaultBean.adicionarState or defaultBean.editarState}">
				<f:facet name="header">
					Dados do Usuário
		        </f:facet>
				<ui:insert name="addUpdateBlock">
				</ui:insert>
			</rich:panel>
		</a4j:form>
	</a4j:outputPanel>
</body>

Nosso template se resume em dois blocos, um bloco para pesquisa e exibição dos resultados (searchlistBlock):
SearchlistBlock

e outro bloco para o formulário de inclusão e edição de cada registro (addUpdateBlock):
AddUpdateBlock

Estes blocos substituem as páginas que a velha escola sempre pregou, assim ao se pensar em navegar entre views (telas) nós não mais navegaremos entre páginas (recursos físicos), mas sim entre blocos (recursos lógicos) dentro daquela mesma página. Estes blocos serão gerenciados por estado(s) no managed bean e não mais regras de navegação do faces-config.xml, assim sempre que quisermos “mudar de tela” nós alteramos o estado atual no managed bean e atualizamos parte da página com AJAX escondendo os blocos desnecessários e exibindo os blocos correspondentes à nova view.

Reparem no template que os blocos somente serão renderizados (através do atributo rendered do componente rich:panel) de acordo com o estado atual da view.

Meu managed bean será como qualquer outro, porém eu terei um atributo para representar o estado atual da view (tela) e alguns métodos para expor este estado de maneira legível, logo meu managed bean será algo como:

[UsuarioCrudBean.java]

public class UsuarioCrudBean {

	public static final String PESQUISAR_STATE = "pesquisar";
	public static final String ADICIONAR_STATE = "adicionar";
	public static final String EDITAR_STATE = "editar";

	private String currentState = PESQUISAR_STATE;
	private String nome;
	private Usuario usuario;
	private List<Usuario> usuarios = new ArrayList<Usuario>();
	private UIPanel panelForm;
	// métodos gets e sets

	/**
	 * Pesquisa usuários por nome
	 */
	public void pesquisar() {
		this.setCurrentState(PESQUISAR_STATE);
		this.usuarios = UsuarioRepositorio.findUsuarioByNome(this.nome);
	}

	/**
	 * Prepara view adicionar
	 */
	public void prepareAdicionar() {
		this.clear();
		this.setCurrentState(ADICIONAR_STATE);
	}

	/**
	 * Adiciona usuário
	 */
	public void adicionar() {
		UsuarioRepositorio.add(this.usuario);
		this.pesquisar();
	}

	/**
	 * Prepara view editar
	 */
	public void prepareEditar() {
		this.setCurrentState(EDITAR_STATE);
	}

	/**
	 * Edita usuário
	 */
	public void editar() {
		// já edita diretamente na lista (a lista está como static)
		this.pesquisar();
	}

	/**
	 * Exclui usuário
	 */
	public void excluir() {
		UsuarioRepositorio.delete(this.usuario);
		this.pesquisar();
	}

	/**
	 * Referente ao botão voltar
	 */
	public void voltar() {
		this.clear();
		this.pesquisar();
	}

	/**
	 * Limpa atributos
	 */
	private void clear() {
		this.nome = "";
		this.usuario = new Usuario();
		this.cleanSubmittedValues(this.panelForm);
	}

	/*
	 * Métodos que expõem o estado à página
	 */

	public boolean isPesquisarState() {
		String state = this.getCurrentState();
		return (state == null || PESQUISAR_STATE.equals(state));
	}
	public boolean isAdicionarState() {
		return ADICIONAR_STATE.equals(this.getCurrentState());
	}
	public boolean isEditarState() {
		return EDITAR_STATE.equals(this.getCurrentState());
	}

	/**
	 * Limpa os componentes filhos para que depois eles possam ser recriados
	 * @param component
	 */
	protected void cleanSubmittedValues(UIComponent component) {
		component.getChildren().clear();
	}
}

As regras de navegação serão gerenciadas internamente pelo managed bean, a página (jsp, xhtml etc) deve trabalhar em cima dos métodos expostos pelo managed bean, e não do atributo currentState em si, ou seja, para a página não importa como está implementada as regras de navegação, a página somente precisa conhecer qual o estado atual para que assim ela possa renderizar ou não seus componentes.

Nossa página de CRUD utilizará o template myCrudTemplate.xhtml como base, segue abaixo o código fonte da página somente com o bloco de edição:

[usuarioCrud.xhtml]

<ui:composition template="/pages/myCrudTemplate.xhtml">

	<!-- passa parâmetro para o template -->
	<ui:param name="defaultBean" value="#{usuarioCrudBean}" />

	<ui:define name="title">
		Cadastro de Usuários
		<t:saveState id="_bean" value="#{usuarioCrudBean}" />
	</ui:define>

	<ui:define name="searchlistBlock">
		<!-- bloco de pesquisa -->
	</ui:define>

	<ui:define name="addUpdateBlock">
		<h:panelGrid columns="2" id="panel2" binding="#{usuarioCrudBean.panelForm}" columnClasses="odd-row,even-row">
			<h:outputLabel value="Login: "/>
			<h:column>
				<h:inputText value="#{usuarioCrudBean.usuario.login}" size="30" required="true" id="login"
							requiredMessage="Campo Login é obrigatório."
							readonly="#{usuarioCrudBean.editarState}"
							style="#{usuarioCrudBean.editarState ? 'color: gray;' : ''}"/>
				<br/>
				<h:message for="login" errorStyle="color: darkred;"/>
			</h:column>
			<h:outputLabel value="Senha: "/>
			<h:column>
				<h:inputSecret value="#{usuarioCrudBean.usuario.senha}" size="30" redisplay="true"/>
				<br/>
			</h:column>
			<h:outputLabel value="Nome: "/>
			<h:column>
				<h:inputText value="#{usuarioCrudBean.usuario.nome}" size="60" required="true" id="nome"
							requiredMessage="Campo Nome é obrigatório." />
				<br/>
				<h:message for="nome" errorStyle="color: darkred;"/>
			</h:column>
			<h:outputLabel value="Blog: "/>
			<h:column>
				<h:inputText value="#{usuarioCrudBean.usuario.blog}" size="90" id="blog"/>
			</h:column>
			<h:outputLabel value="Ativo?"/>
			<h:column>
				<h:selectOneMenu value="#{usuarioCrudBean.usuario.ativo}" id="ativo"
						requiredMessage="Campo Ativo é obrigatório."
						required="true">
					<f:selectItem itemValue="" itemLabel="[Selecione uma opção]" />
					<f:selectItem itemValue="#{true}" itemLabel="Sim" />
					<f:selectItem itemValue="#{false}" itemLabel="Não" />
				</h:selectOneMenu>
				<br/>
				<h:message for="ativo" errorStyle="color: darkred;"/>
			</h:column>
		</h:panelGrid>
		<a4j:commandButton value="Adicionar" action="#{usuarioCrudBean.adicionar}" rendered="#{usuarioCrudBean.adicionarState}"/>
		<a4j:commandButton value="Editar" action="#{usuarioCrudBean.editar}" rendered="#{usuarioCrudBean.editarState}"/>
		<a4j:commandButton value="Voltar" action="#{usuarioCrudBean.voltar}" immediate="true"/>
	</ui:define>
</ui:composition>

Assim como nossos blocos principais (searchlistBlock e addUpdateBlock) do template, muitos componenentes também são renderizados ou mudam de estado dependendo do fluxo de navegação, um deles por exemplo é o botão “Editar” que somente será renderizado quando nossa view estiver no estado de edição:

<a4j:commandButton value="Editar" action="#{usuarioCrudBean.editar}" rendered="#{usuarioCrudBean.editarState}"/>

Na minha página usuarioCrud.xhtml eu estou passando a referência do managed bean atual como parâmetro para o template para que ele consiga gerenciar os blocos corretamente, isso me possibilita ter um template mais genérico para minhas páginas de CRUDs:

<ui:param name="defaultBean" value="#{usuarioCrudBean}" />

Atentem que eu estou utilizando o componente t:saveState do Myfaces Tomahawk para ampliar o escopo de conversação, com ele eu posso manter meus managed beans como escopo de request enquanto eu navego entre os blocos lógicos, depois de mudar literalmente de página (recurso físico) eu terei aqueles dados removidos da memória do servidor.

<t:saveState id="_bean" value="#{usuarioCrudBean}" />

Outra coisa interessante é que por estarmos sempre trabalhando sob a mesma árvore de componentes (viewRoot) é necessário resetar o estado de alguns componentes ou bloco de componentes quando necessário, pois mesmo que estes componentes não sejam renderizados eles ainda assim mantém o estado anterior.

No nosso caso eu estou sempre limpando o estado do formulário de edição ao clicar no botão “Voltar” da aplicação, que por sua vez faz uma chamada ao método cleanSubmittedValues(), é este método que se encarrega de limpar o estado anterior do formulário:

protected void cleanSubmittedValues(UIComponent component) {
	component.getChildren().clear();
}

Existem outras abordagens para resetar o estado dos componentes de um formulário, eu busquei utilizar a maneira mais simples, porém creio que não seja a mais performática -neste caso-. Mesmo não possuindo a melhor performance ainda assim é -várias vezes- mais rápida que gerar todo uma nova árvore de componentes (utilizado pela velha escola), com toda certeza.

E quais seriam as vantagens dessa abordagem?

Existem várias vantagens em relação a abordagem da velha escola, entre elas podemos destacar:

  • Menor consumo de memória e processamento no servidor, pois estaremos sempre trabalhando sob a mesma árvore de componentes (viewRoot);
  • Menor overhead no cliente (browser), pois estaremos evitando reload completo de páginas;
  • Menor tráfego de dados na rede, muito menor, pois estaremos apenas transportando pequenos blocos de página;
  • Maior escalabilidade e performance na aplicação;
  • Diminui drasticamente o número de pontos de manutenção na aplicação (páginas, arquivos de configuração etc);
  • Renderização dos componentes muito mais rápida, sejam parciais ou grandes blocos lógicos;
  • Maior usabilidade e controle de renderização parcial nas páginas;
  • Evita o problema do botão voltar (back button);
  • Evita resubmissão do formulário após um refresh (F5);
  • Managed beans realmente mais inteligentes;
  • Exibição das páginas com um aspecto mais leve, possibilitando ainda a utilização de efeitos através de frameworks javascripts;
  • Facilidade em criar classes de managed beans mais genéricas (um CrudBean por exemplo);
  • Melhor controle/tratamento de respostas entre cliente e o servidor (barra de progresso, timed out etc);

Bem, vantagens é o que não falta em relação a velha escola. Provavelmente possamos discutir mais algumas vantagens e até quem sabe desvantagens na lista de discussão do JavaSF.

Concluindo

Mesmo esta abordagem sendo superior a abordagem da velha escola ela ainda assim não é a “bala de prata”, como toda nova abordagem ela deve ser estudada e utilizada com bom senso, haverá momentos em que será mais prático e até melhor efetuar um reload completo de página, ou dividir os blocos lógicos em pequenas páginas para evitar grandes arquivos físicos, enfim, bom senso é algo que sempre deve ser levado em consideração.

Eu não me prendi a utilização dos frameworks ou conjuntos de componentes utilizados pois este não era o intuito do post, isso é algo simples e acredito que a maioria dos leitores não tenham dificuldades em relação a isso. Além do mais é possível implementar isso não somente com o Richfaces/Ajax4jsf, mas com qualquer outro framework ou conjuntos de componentes AJAX, por exemplo, no último projeto que participei implementamos nossas páginas utilizando-se desse conceito com Myfaces Trinidad, que por sinal está funcionando muito bem.

É bastante notório a velocidade na renderização das páginas, sendo aconselho vocês a fazerem alguns testes com esta abordagem e observarem o quanto mais rápido se torna o desenvolvimento e a renderização das páginas. Eu fiz a aplicação o mais simples possível para demonstrar essa abordagem, com certeza ainda é possível otimizar as requisições AJAX através de configurações do Ajax4jsf e do Richfaces, você pode ver mais sobre isso na documentação do mesmo.

Eu estou disponibilizando esta aplicação exemplo como prova de conceito, é um projeto do Eclipse (MyEclipse para ser mais exacto), sendo basta importa-lo e efetuar o deploy da aplicação.

Tagged with: , , , , , , , , , , , , , , , , , , , ,
Posted in Boas Práticas, Desenvolvimento Ágil, Engenharia de Software, Java, JavaScript, JEE, JSF, web
89 comments on “Utilizando AJAX com JSF de maneira eficiente
  1. Daniel Vidal says:

    Muito boa abordagem sobre os benefícios que o AJAX oferece nas nossas aplicações, em especial em JSF. Claro que não podemos criar aplicações em uma só página, ai vai o bom senso dos programadores… ;)
    Abraços

  2. Rafael Ponte says:

    A idéia não é criar uma aplicação somente em uma única página, longe disso. Mas sim substituir conjuntos de telas (páginas) por blocos lógicos dentro da mesma página. Por exemplo, um CRUD muitas vezes se divide entre 2 a 4 páginas, neste caso teríamos uma única página dividida em 2 a 4 blocos para cada CRUD.

  3. Itamar says:

    Ponte,

    Parabens . Este é um exemplo que eu estava procurando para começar a usar o rich pois sou iniciante.
    Eu não sei usar facelets é tranquilo passar para jsp ?

    Muito Obrigado.

  4. Rafael Ponte says:

    Sim, facelets é bem simples. Utilizar JSF hoje sem facelets é até “feio”, rss.. Um bom lugar para começar a aprender facelets é no artigo da devmedia, http://www.devmedia.com.br/articles/viewcomp.asp?comp=5332

  5. Fred says:

    Boa … muito boa essa sua tacada.
    Vc falou certo Rafael!

    Ajax ainda é usado de uma meio fraca sem explorar sua capacidade 100%. Seu post mostrou que se vc fizer um projeto bem modular e reutilizável, pode-se sim explorar o Ajax de uma forma incrívelmente legal. Como vc disse, o JSF ajuda mesmo!
    Tenho estudado e trabalhado com aplicações Ajax com Java, Php e Rails, e eu particularmente acho incrível essa capacidade do JSF em permitir vc reutilizar modulos e de renderizar componentes e seu sub-componentes inteiros e não somente um componente ou apenas um atributo específico como no php+html.

    Muito legal mesmo seu post!

  6. Bruno says:

    Olá Rafael
    Primeiro gostaria de parabeniza-lo e seus parceiros pelo serviços prestados nos seus respectivos blogs. Vocês sempre abordando assuntos interessantes no meio do desenvolvimentos e sempre nos oferecendo uma excelente visão de um todo.
    Meu nome é Bruno, tenho 21 anos e estou cursando Sistemas de Informação aqui em Jundiaí. Estou no meu último ano (4º ano), ou seja, ano de TCC…e juntamente com um companheiro de classe, resolvemos abordar uma tecnologia java…Avaliação comparativa dos frameworks de interface, JavaServer Faces vs Tapestry, iremos desenvolver um prototipo e em cima disso fazer nosso trabalho. Gostaria, se possivel, de algumas dicas, algum tipo de ajuda que possa ser útil para esse nosso projeto.
    Desde já agradeço
    Forte abraço e obrigado por tudo.

  7. Rômulo says:

    Olá Rafael! Você usou aí qual versão do richfaces? Não sei se é isso, mas eu to usando o Facelets 1.2 e o Richfaces 3.2 e não funciona. O container não consegue carregar o richfaces e acontece um erro como esse:
    http://www.guj.com.br/posts/list/58628.java

    Se soube de algo, valeu!

  8. Rômulo Augusto says:

    Não sei se vc tentou usar com Spring, mas eu tentei e me deparei com um problema:
    Na declaração do meu bean, declarei também uma ‘managed-property’ que é utilizada pelo Spring.
    Apenas por causa disso, eu tenho que colocar meu bean com escopo ‘session’, pq na troca de painéis os botões param de funcionar.

    Tem como corrigir isso?

  9. Rafael Ponte says:

    Olá Romulo, eu não entendi sua pergunta. De que parte exatamente você está falando? :)

  10. Rômulo Augusto says:

    Por exemplo: O managed bean tem uma propriedade q é injetada pelo Spring.
    No painel da pesquisa aperte no botao adicionar. Se o managed bean estiver com escopo ‘request’, os botoes do painel de cadastrar nao funcionam, apenas dão refresh na página, e aí volta pra o painel da pesquisa.

    Se eu tirar, lá no faces-config.xml, o ‘managed-property’ q o Spring usa, esse problema nao ocorre.

    Ja testei usando xml e annotation do Spring.

  11. Rafael Ponte says:

    Isso é muito estranho, eu não tive problemas com isso. Estranho mesmo. Você já fez testes com o componente t:saveState do Myfaces Tomahawk?

    Abraços!

  12. Rômulo Augusto says:

    Se eu usar o t:saveState ocorre isso:
    Variable ‘myBean’ refers to a Spring bean which by definition is not writable.

  13. Murilo Aguiar says:

    Rafael Ponte, ótimo artigo. Vou começar outro projeto nesse momento, qual sua opinião com relação a inumeros acessos a uma página com essa estrutura, utilizando rich/ajax? posso colocar isso em produção sem medo? ou tenho que dar um tunning no servidor tb? Valeu e Abraço.

  14. Rafael Ponte says:

    Olá Murilo, o ideal é que você levante metas e requisitos sobre a escalabilidade da tua aplicação, assim fica mais fácil saber a configuração de um servidor decente, se há necessidade de algum tunning no teu servidor ou algo do tipo.

    Utilizando-se dessa abordagem você terá uma melhor escalabilidade e performance do que utilizando a maneira convencional, você poderá até melhorar isso com mais algumas configurações e otimizações como por exemplo uma simples paginação sob demanda.

    Enfim, como citei no post as vantagens existem, mas não deixe de usar o bom senso em certos momentos.

    Abraços.

  15. Murilo Aguiar says:

    Rafael… me explica esse UIPanel… não consigo rodar com ele .. da que tem uma referencia NULL no panelForm.. qual a funcionalidade??? pq vc usou??? valeu d++

  16. Murilo Aguiar says:

    cara seguinte!!! to só te encehndo hein .. funcionou mais sem o UIPanel .. e outra ele não altera o datatable… e nao da nenhum erro monitoro pelo firebug a requisição vai mas nao altera nada nem na pesquisa nem na paginação … abração … desculpa o amadorismo kkkk

  17. Rafael Ponte says:

    Murilo,

    Esse UIPanel é um binding para o panel do formulário, assim você poderá resetar o estado da árvore de componentes sempre que possível, pois como você não muda de página e consequentemente não muda de viewroot o estado da árvore é mantido entre requests, logo é necessário reseta-lo ou simplesmente altera-lo quando necessário.

  18. Rafael Ponte says:

    Não altera o datatable em que momento? Não entendi bem o teu problema :)

  19. Murilo says:

    Cara acredite se quiser … o que esta diferente do meu codigo para o seu é só a consulta que eu faço no banco com jpa … mas no IE e no Konqueror funciona mas no firefox não puts kkk já aconteceu com vc???

  20. Pablo Borges says:

    parabens, otimo artigo continue assim rafael. Abraços

  21. Clériston Martinelo says:

    Olá Rafael, como já disse parabéns pelo artigo.
    Eu fiz um projeto semelhante e tentei utilizar internacionalização e não consegui. Onde utilizo o ?

    Desde já agradeço a resposta

  22. Rafael Ponte says:

    Olá Clériston, não entendi tua pergunta. Mas sobre internacionalização, você consegue com algumas configurações no faces-config.xml e arquivos properties para cada idioma.

  23. Clériston Martinelo says:

    entao acho o blog nao permitiu eu adicionar uma “tag” na minha pergunta…

    Eu queria saber onde coloco o f : loadbundle ??

  24. Rafael Ponte says:

    Você está utilizando JSF1.1 ou JSF1.2? Na verdade eu te aconselho fortemente a entrar na lista de discussão JavaSf, http://groups.google.com/group/javasf , lá com certeza você terá mais detalhes sobre a configuração :)

  25. Krusst says:

    so uma duvida
    esta parte do codigo

    var infoWindowAMShown = false;
    var infoWindowAMTimer;
    function showModalInfoWindow()
    {
    infoWindowAMTimer = setTimeout(“if(!infoWindowAMShown){Richfaces.showModalPanel(‘ajaxLoadingModalBox’);infoWindowAMShown=true;}”, 500);
    }
    function hideModalInfoWindow()
    {
    if (infoWindowAMShown) {
    Richfaces.hideModalPanel(‘ajaxLoadingModalBox’);
    infoWindowAMShown=false;
    } else {
    if(infoWindowAMTimer)
    clearTimeout(infoWindowAMTimer);
    }
    }

    seria obrigatoria?
    poderia me dar uma esclarecida nela

    parabens pelo tutorial, sao tutoriais que nem esse que estao faltanto!

    abs
    T+

  26. Rafael Ponte says:

    Olá Krusst, na verdade isso não é obrigatório. Eu somente o coloquei para criar um delay antes de exibir um modalpanel com uma mensagem no estilo “carregando..”. Assim, a mensagem somente irá aparecer para o usuário caso realmente demore. Como foi uma aplicação exemplo e provavelmente será testada localmente, as requisições são muito rápidas, logo fica chato ver a mensagem de “carregando..” aparecendo e sumindo rapidamente no browser.

  27. Clériston Martinelo says:

    Olá Rafael!

    Acho q dá pra fazer um Bean genérico utilizando generics não é?
    Pois a única coisa que muda de um bean para o outro é o “Registro atual” (neste exemplo é a variável usuario) e a lista de registros (neste exemplo é a variável usuarios).
    Seria uma boa idéia nao é?

  28. Sandro says:

    Oi Rafael,

    Ótima matéria mesmo, parabéns.

    Estou com um pequeno problema, pois estou usando JSF 1.1 e ele não aceita a linha:

    Qual a sua dica para solucionar esse problema?

    []´s

  29. Raphael says:

    Boa tarde Chará!

    Muito bom seu tutorial, porém estou com a seguinte dúvida:
    - Como faço para utilizar o estilo do input (Azul bem clarinho com gradiente) baseado no estilo padrão (Skin) do richfaces, conforme imagens exibidas no seu post.
    Fico no aguardo de uma resposta…

  30. Raphael says:

    Esqueci de mencionar também dos estilos dos botões, pois quando executo a aplicação, os botãos não ficam com o background azul bem claro.
    Meu ambiente: Eclipse Europa 3.3; Richfaces 3.2; Facelets 1.1.4; e tomahawk (Versão utilizada neste post)

  31. Sandro says:

    Cara estou com mais uma dúvida.
    Criei uma tela de login e estou usando a seguinte tag para validação:

    Meu problema é que nesse caso eu preciso que ele vá para outra pagina mesmo.

    faces.congig.xml:

    /pages/login.xhtml

    #{loginHandler.doLogin}/from-action>
    sucesso
    /pages/usuarioCrud.faces

    O problema é que ele valida e fica na mesma página.

    Agradeço a ajuda.

  32. Raphael says:

    Boa tarde Rafael!

    Gostaria de saber onde você declarou os métodos: adicionarState, editarState e pesquisarState, pois não estou encontrando no bean utilizado nesse exemplo.
    Fico no aguardo!

  33. Rafael Ponte says:

    Olá Raphael, são os métodos isAdicionarState(), isEditarState() e isPesquisarState(). Métodos que começam com get*, set* e is* estão dentro da especificação JavaBeans.

    Abraços!

  34. Raphael says:

    Bom dia Raphael!

    Valeu mesmo, o problema foi resolvido!!!

    Abraços!

  35. Fred says:

    Pefeito, esta sanando muitas duvidas minhas sobre como fazer as coisas!

  36. jopss says:

    Olá, nao estou conseguindo usar seu exemplo com JSF 1.1, como vc disse essa versão é somente para 1.2….. mas não há como usar Ajax com JSF 1.1 ????

  37. Rafael Ponte says:

    Sim, é possível utilizar AJAX com JSF1.1, levando em consideração que seu framework ou conjunto de componentes AJAX trabalhe com JSF1.1

    Se não me engano, a partir da versão 3.2 do Richfaces ele não suporta mais JSF1.1, logo será necessário trabalhar com uma versão anterior.

    Abraços e boa sorte.

  38. Jonny says:

    Envia por favor para meu email os códigos do .xhtml da parte
    Pois estou sem saber como configurar algumas tags.

  39. George Queiroz says:

    é as velhas formas de gerenciamento de formulários voltando ahahha, ou seja, gerencia estado e ativa ou não algo :)

    ai pompom, acho q vc é re-incarnação de algum veio erudita

    ahhaha

    eh nois

  40. luis ednaldo says:

    importei sua aplicação de exemplo richfaces ajax4jsf , mas quando rodo o index . jsp ele da erro 4004 dizemdo que não achou o index.faces.
    om que pode ta acontecendo?

  41. Wagner Eliakim says:

    Primeiramente parabéns pelo artigo. Já vi os comentários sobre a utilização consciente da técnica e concordo totalmente, pois como você mesmo citou, o artigo não é uma receita de bolo. rsrsrs…

    Por isso gostaria de saber se você tem uma solução que estou buscando há mais ou menos um mês, para que possamos aperfeiçoar a estrutura que você demonstrou.

    O problema é o seguinte: Pelo que observei para utilizar-mos tal estrutura, é preferível que a configuração do javax.faces.STATE_SAVING_METHOD esteja como server pois se não deveremos implementar a classe java.io.Serializable em nossos managed`s beans o que não se torna a coisa mais interessante. Então, como com o server a estrutura da árvore de componentes fica no servidor, e não no cliente, quando a sessão do usuário termina por inatividade, por exemplo, se o usuário fizer qualquer requisição ajax, é gerada uma exceção do tipo javax.faces.application.ViewExpiredException que torna a aplicação inativa para qualquer outro cliente. Você sabe como tratar esta exceção? Você já teve algum problema semelhante?

    Desde já agradeço sua ajuda e atenção.

  42. Edson Alves says:

    Parabéns pelo post, estou sentindo dificuldades para rodar a aplicação, pois uso o eclipse 3.4 j2ee e faltam jars para a devida aplicação.
    Poderia disponibilizar um arquivo .war ,da aplicação, configurado para o eclipse?

  43. Cristiano Pires says:

    Já usei richfaces. Achei legal.
    Mas pra ajax e jsf prefiro utilizar com gwt. Tenho usado muito facelets + gwt.

    É bem produtivo e tenho tido ótimos resultados.
    Acho que é a melhor opção pra usar ajax no jsf.

    Todavia é apenas minha opinião!

    O richfaces tem um módulo pra utilizar gwt, o gwt4jsf. Mas eu não gosto!

  44. Marcius Brandão says:

    O Clériston Martinelo falou sobre um bean generic, por aqui eu tô usando esse que eu fiz (um workaround :-D ) com preguiça de ficar repetindo codigo, você pode aproveitar o código se quiser:

    PS: pra usar seria tipo assim :

    public class FuncionarioMB extends ManagedBeanGeneric{
    //nada aqui :-D
    }

    /**
    *
    * @author Marcius Brandão
    */
    public class ManagedBeanGeneric {

    private Class type;
    private String className;
    private IDAO dao;
    private T selected;
    private List list;
    private List listItems;
    private OQL oql;

    /** Creates a new instance of BeanManagedGeneric */
    public ManagedBeanGeneric() {
    this.type = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    this.className = this.type.getSimpleName();
    dao = DAOFactory.getInstance().getDAO(type);
    oql = new OQL(type);
    }

    public String startAdd() {
    selected = (T) dao.newInstance(type);
    return “gotoNew” + className;
    }

    public String finishAdd() {
    dao.save(selected);
    list = null;
    return “gotoListOf” + className;
    }

    public String startEdit() {
    return “gotoEdit” + className;
    }

    public String finishEdit() {
    dao.save(selected);
    list = null;
    return “gotoListOf” + className;
    }

    public String remove() {
    dao.delete(selected);
    list = null;
    return “gotoListOf” + className;
    }

    public List getList() {
    if (list == null) {
    list = (List) dao.query(oql.getOQLCommand());
    }
    return list;
    }

    public T getSelected() {
    return selected;
    }

    public void setSelected(T selected) {
    this.selected = selected;
    }

    public List getSelectItems() {
    if (listItems == null) {
    listItems = new LinkedList();
    List lista = dao.query(oql.getOQLCommand());
    for (T item : lista) {
    SelectItem si = new SelectItem(item, item.toString());
    listItems.add(si);
    }
    }
    return listItems;
    }

    public void addFilter(String propertyName, String propertyValue){
    oql.addFilter(propertyName, propertyValue);
    }
    }

  45. Marcius Brandão says:

    ôpa , esqueci de formatar :

    import dao.DAOFactory;
    import dao.IDAO;
    import dao.oql.OQL;
    import java.io.Serializable;
    import java.lang.reflect.ParameterizedType;
    import java.util.LinkedList;
    import java.util.List;
    import javax.faces.model.SelectItem;

    /**
    *
    * @author Marcius
    */
    public class ManagedBeanGeneric {

    private Class type;
    private String className;
    private IDAO dao;
    private T selected;
    private List list;
    private List listItems;
    private OQL oql;

    /** Creates a new instance of BeanManagedGeneric */
    public ManagedBeanGeneric() {
    this.type = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    this.className = this.type.getSimpleName();
    dao = DAOFactory.getInstance().getDAO(type);
    oql = new OQL(type);
    }

    public String startAdd() {
    selected = (T) dao.newInstance(type);
    return “gotoNew” + className;
    }

    public String finishAdd() {
    dao.save(selected);
    list = null;
    return “gotoListOf” + className;
    }

    public String startEdit() {
    return “gotoEdit” + className;
    }

    public String finishEdit() {
    dao.save(selected);
    list = null;
    return “gotoListOf” + className;
    }

    public String remove() {
    dao.delete(selected);
    list = null;
    return “gotoListOf” + className;
    }

    public List getList() {
    if (list == null) {
    list = (List) dao.query(oql.getOQLCommand(),0,100);
    }
    return list;
    }

    public T getSelected() {
    return selected;
    }

    public void setSelected(T selected) {
    this.selected = selected;
    }

    public List getSelectItems() {
    if (listItems == null) {
    listItems = new LinkedList();
    List lista = dao.query(oql.getOQLCommand());
    for (T item : lista) {
    SelectItem si = new SelectItem(item, item.toString());
    listItems.add(si);
    }
    }
    return listItems;
    }

    public void addFilter(String propertyName, String propertyValue){
    oql.addFilter(propertyName, propertyValue);
    }
    }

  46. Dirceu Sobrinho says:

    Olá, Rafael, Parabéns pelo artigo!

    utilizei essa abordagem em um projeto aqui! sendo no meu caso, eu gostaria de a melhorar a performance da minha aplicação alterarando os relacionamento EAGER para LAZY, para isso eu iria utilizar a implementação do padrão Open Session In View fornecida pelo SPRING, como essa abordagem é baseada em ajax, quando aciono um evento ajax após eu receber uma resposta, o OSIV fecha a sessão.

    Eu tou dando olhada em umas implementação que deixa a sessão por um periodo maior (Long session) mas ainda não achei nada 100% funcional.

    Gostaria de saber como vc trata relacionamentos LAZY com essa abordagem baseada em AJAX/JSF/RICHFACES?

    att. Dirceu

  47. Rafael Ponte says:

    Olá Dirceu,

    Eu sempre tento utilizar-me de LAZY nos relacionamentos, e quando preciso iterar sobre um relacionamento de um objeto que não está mais “managed”, ou seja, ele está “detached” eu o pesquiso novamente no banco, assim consigo iterar seu relacionamento normalmente.

    É chatinho, mas se faz necessário.

    Outra solução, seria a utilização o Myfaces Orchestra, ele além de manter o estado conversacional dos managed beans ele também mantém o contexto de persistência, logo você não terá mais problemas com LazyInitiationException.

    A utilização do JBoss Seam é outra solução até melhor que o Myfaces Orchestra.

    Abraços e boa sorte.

  48. Excelente material. Estou estudando sobre JSF, para começar um projeto novo aqui na empresa e logo começaram a falar sobre facelets, então nos coments vc mandou um outro excelente link sobre facelets.

    Este artigo REALMENTE ajudou a comunidade, vejo isso por mim.
    Muito obrigado.

    Vou fazer alguns testes com o fonte disponibilizado.

  49. Robson says:

    Olá Rafael! Em primeiro lugar parabéns pelo blog e pelos excelentes posts aqui escritos. Gostei muito desse artigo, mas gostaria de saber se essa abordagem é saudável quando temos páginas de crud com muitos campos? Não tornaria a manutenção pior?

  50. Rafael Ponte says:

    Robson,

    Antes de mais nada, obrigado!

    Bem, não há problema algum, pode usar sem medo. Caso a página seja muito grande então aconselho-te a quebra-la em páginas menores e fazer os devidos “includes”, isso facilita e muito a manutenção.

    Além do mais, não importa se você está escrevendo uma página de CRUD ou não, essa abordagem serve para qualquer tipo de página.

    Abraços.

  51. Fabiano Almeida says:

    Olá Rafael!

    Parabéns pelo post. Muito interessante a sua abordagem. Estive fazendo testes com base nos seus arquivos disponibilizados. Porém eu não estou obtendo sucesso. Postei essa dúvida aqui:
    http://www.guj.com.br/posts/list/95585.java#627652
    Só que até agora ninguém respondeu. Teria como você me ajudar?
    Obrigado.

  52. Felipe says:

    Rafael,

    muito legal os seus tutoriais, e abordagem sobre as ferramentas e melhores praticas de desenvolvimento.

    Estou iniciando com richfaces e tudo mais..porem nao consegui finalizar esse tutorial.
    deu erro.
    com.sun.facelets.FaceletException: Error Parsing /usuarioCrud.xhtml: Error Traced[line: 15] Invalid byte 2 of 3-byte UTF-8 sequence.
    at com.sun.facelets.compiler.SAXCompiler.doCompile(SAXCompiler.java:

    Poderia me ajudar?

    abracos

    Felipe M

  53. Maeda says:

    Felipe, isso provavelmente é alguma acentuação q vc usou nos comentários do xhtml…

  54. Diego Lins says:

    Olá Ponte.

    Muito bom o post, parabéns, até estou utilizando ele, fiz algumas alterações para atender minhas necessidade e consequentimente causou alguns problemas que posteu no guj http://www.guj.com.br/posts/list/121589.java,
    Você poderia por favor dar uma olhada ?

    Obrigado

  55. Carlos Amaral says:

    Ola Rafael.
    Será que voce não poderia postar o link original de onde voce copiou este exemplo ?

    Baseado no seu não estou conseguindo fazer rodar… Está faltando muita informação, mormente para quem está começando agora….

    Obrigado

  56. Rafael Ponte says:

    Olá Carlos,

    Na verdade eu não copiei este post nem o exemplo do mesmo. Eu mesmo o criei. Mas vale salientas que este (State-Driven Navigation) não é um conceito novo de se trabalhar.

    No último paragrafo do post há um link para você poder baixar a aplicação de exemplo com todo o código utilizado e demais configurações. Infelizmente eu não adicionei as libs necessárias pois o projeto iria ficar maior do que o necessário.

    Mas basicamente as libs são do Mojarra 1.2, Richfaces e Myfaces Tomahawk (obviamente com suas dependências).

  57. Márcio Neves says:

    Estou utilizando o exemplo e não consigo fazer funcionar com escopo “request” e quando utilizo dois formulários, por exemplo “Usuario” e “Cidade” o sistema se perde. Os botões não funcionam e os dados não são salvos.

    Quando utilizo o escopo “session” o sistema se perde quando utilizo dois formulários. Rafael você pode me ajudar ??

  58. Daniel Bussade de Almeida says:

    Olá Rafael, muito interessante o exemplo. Baixei a aplicação exemplo, e funcionou perfeito, porém quando fui tentar montar uma aplicação com a mema idéia, na hora de cadastrar o Usuario por exemplo, so funciona se meu ManagedBean tiver no escopo session, se eu colocar escopo request, quando clico em Adicionar ele nao invoca a ACtion, simplesmente voltar para o FormAnterior.

    Sabe porque acontece esse problema?

  59. Alex Egidio says:

    Parabéns pelo excelente post Rafael me ajudou muito!
    Eu queria acrescentar uma coisa:
    Comigo o datascroller não funcionava corretamente, toda vez que ele era selecionado era como se fizesse uma nova requisição ao bean e uma nova busca. Para corrigir isso tive que adicionar a tag:

  60. Rodrigo Silva says:

    Apesar dos elogios já obtidos pelo post, aí vai mais um:

    Parabéns! Excelente post!

    Estou iniciando em JSF, e finalmente consegui entender a mudança no paradigma da navegação.
    Ainda estava preso à velha escola.
    Espero que com essa mudança, eu obtenha mais sucessos.

    Abraço!

  61. Victor says:

    Rafael,

    estou seguindo seu tutorial e estou tendo o seguinte problema:

    Quando carrego a página com a listagem e clico no botão adicionar para ele esconder o painel de listagem e mostrar o de inclusão funciona tudo bem, porém ao tentar executar qualquer outra ação após a re-renderização da tela sou redirecionado para a tela de listagem novamente sem nem ter chego no meu Bean.

    Fiz um teste e coloquei esse botao de confirmação de inclusao na tela de listagem e fiz a inclusão no bean em hard code e funcionou tudo bem. O problema só acontece quando vou para o bean e volto para a página.

    Alguma idéia?

    Obrigado.

  62. Arthur Ronald F D Garcia says:

    Parabéns pelo artigo,

    Não conhecia essa técnica. Parece ser bem eficiente. Vc poderia informar algum recurso (link) onde eu poderia aprofundar-me sobre o mesmo ??

    Agradeço desde já e obrigado, em nome da comunidade Java, por fortalecer a comunidade.

  63. Helder says:

    Cara, tenho que te parabenizar pelo artigo.
    Percebi o quanto é eficiente utilizar essa abordagem desde que comecei a utilizá-la.
    Pretendo me aperfeiçoar na utilização dessa prática.

  64. Oscar JCN says:

    Ola, muito legal essa abordagem que você colocou aqui
    eu testei e funcionou bem, mas substitui pelo
    Aparentemente deu certo!
    Existe algum efeito negativo na aplicação?
    fiz isso pois não quis utilizar o tomahawk
    abraço

  65. Rafael Ponte says:

    Oscar,

    Acho que seu comentário saiu pela metade! Não estou conseguindo entende-lo.
    Um abraço.

  66. Oscar jcn says:

    Realmente, sumiu o código que eu coloquei (como faz pra ele aparecer ?).
    a4j:keepAlive beanName = “#{usuarioCrudBean}” ajaxOnly=”true” no lugar do
    t:saveState id=”_bean” value=”#{usuarioCrudBean}”
    você sabe se tem algum ponto negativo?

  67. Rafael Ponte says:

    Oscar,

    O a4j:keepAlive e t:saveState tem o mesmo funcionamento e não deveria haver diferença entre eles. Porém o t:saveState é bem mais flexível pois te permite prolongar o escopodos objetos de granulidade mais fina (propriedades do managed bean). O que na maioria dos casos é o que você precisa.

    Um problema de prolongar o escopo do managed bean inteiro (seja com a4j:keepAlive ou t:saveState) é que os componentes (DAOs, Services etc) injetados no managed bean acabam sendo serializados e coisas bizarras começam a acontecer. Fora que você é obrigado a serializa-los quando você não deveria.

    Enfim, depende muito do caso e de como você trabalha. Mas minha preferência sempre foi pelo Tomahawk. É bem simples coloca-lo no projeto: basta jogar o jar no diretorio lib e importa-lo na página.

    Um abraço.

  68. Benigno says:

    Rafael,

    Tenho uma dúvida, você não utiliza reRender, não consegui compreender como os “blocos” são renderizados quando mudam o estado.

  69. Oquendo says:

    Rafael, fiz um exemplo aqui baseado no seu, no entanto usei o Spring para injetar dependências, mas só funciona quando o spring está com escopo de session:
    @Scope(“session”), se colocar request, os links dos datables, não funcionam mais; trabalhei então com o keepalive, como vc já tinha comentado, tive q serializar muitas coisas q acho q não precisaria, bom, o fato é q os botões do datatable voltaram a funcionar, no entanto, o hibernate não persiste mais o objeto no banco. Tentei usar o saveState, mas, quando vou fazer alguma operação na página xhtml, tenho o erro: Variable ‘fController’ refers to a Spring bean which by definition is not writable. Já estou nisso há vários dias, estou pensando em abandonar o Spring, não sei se o problema é dele, na verdade não sei mais o q fazer. Por favor, poderia me ajudar nesse questão?

  70. Sidnei says:

    E ae Rafael, acho legal o uso do AJAX mas creio que a sua utilização deve ser levada em conta o custo de uma requisição ajax que não é baixa caso o sistema tenha alta concorrência pode ser um ponto negativo. PArticipei do desenvolvimento de um sistema onde em cada alteração do estado de um select (combo) havia uma requisição para alterar o valor da propriedade no MBean utilizando o a4j:support achei desnecessário e custoso ao projeto porém ninguém me ouviu e segue pesado…

    Abraços parabéns pelo post

  71. Matheus says:

    Rafael, o seu tutorial tem sido bastante útil para meus estudos de JSF. No entanto, estou tendo severas dificuldades para configurar o deployment descriptor corretamente. Você poderia me indicar um link que tenha algum material a respeito disso? Agradeço desde já! =D

  72. Rafael Ponte says:

    Matheus,

    Fico em saber que meus posts tem te ajudado :-)

    Sobre um deployment descriptor você pode ver um exemplo aqui, https://github.com/rponte/jsf-loja-project/blob/master/WebContent/WEB-INF/web.xml

    Nele há a configuração do JSF1.2, Richfaces 3.3.3 e Spring 3.x. Se possível eu aconselho você baixar toda o projeto, importa-lo no Eclipse (Galileo ou superior) e roda-lo.

    ABraços e boa sorte.

  73. Raphael says:

    Por favor, aprenda a usar crase!

  74. Charles says:

    Ótimo post Rafael, muito bom msm!!!!

    Estou utilizando teu post como base para uma aplicação (JSF+FACELETS+JPA+SPRING+HIBERNATE) aq no trabalho ele tem me ensinado e ajudado muito!!!

    Preciso de tua opnião/orientação com relação a navegação entre os CRUDs. Na minha aplicação há um menu dos CRUDs (Cliente, Fornecedor, Produto, etc.) mas qual a melhor solução para mudar de CRUD?

    Muito obrigado.
    Att.
    Charles

  75. Rafael Ponte says:

    Olá Charles,

    Que bom que o post está te ajudando de alguma forma. Fico feliz com isso!

    Pela minha experiência eu aconselho a navegação do menu ser a mais simples possível. Nem necessariamente precisa ser um componente JSF a gerar o menu, pode ser somente XHTML+CSS mesmo. Mas enfim, o que quero dizer é que utilize links (urls) mesmo para o menu, ou se estiver partindo para navegação do próprio faces tente usar REDIRECT. Ajax não é uma boa para esse tipo de navegação.

    O ideal é tentar perceber quando e se é viável/necessário utilizar Ajax em toda ou determinadas partes da aplicação.

    Um abraço.

  76. Charles says:

    Boa tarde Rafael.

    Sou muito ruim de interface web (muito mesmo!) assim acabo tentando o mais fácil na hora de moldar as telas. Prefiro algo encapsulado tipo o richfaces =D

    Contudo, vou tentar o XHTML+CSS conforme tua orientação pois até agora você tem me dado ótimas dicas! =))))

    Dúvida: quando carrego a aplicação pela primeira vez no IE8 e clico em alguma opção que aparece o ‘Aguarde Processamento’, que você criou, ele simplesmente não desaparece. Se em seguida abro outra aba do navegador não ocorre o mesmo problema. Sabe o que pode ser feito para corrigir isso?

    Muito obrigado.
    Att.
    Charles

  77. Cristiano says:

    Olá Rafael,

    Estou trabalhando em um sistema que funciona semelhante a esta estrutura que você publicou, porém estou tendo problemas com Ids duplicados e motivo é porque todas as telas estão sendo incluídas na index.xhtml, acontece que o jsf acaba se perdendo na hora de reconstruir a árvore de componentes, pois nunca é feito um request, sempre é utilizado o Ajax request.
    Já passou por algum problema semelhante ?

  78. Rafael Ponte says:

    Cristiano,

    Como assim todas as telas estão sendo incluidas na index.xhtml?

  79. Herick says:

    Olá Rafael,

    Estou desenvolvendo um sistema utilizando JSF2.0 e Primefaces.
    Basicamente, minhas telas são constituídas de tabelas de exibição e cadastros utilizando Dialogs.

    Meus dialogs possuem campos required e validators para tratar os erros. Criei um listener que faz essa verificação dos dados antes de salvar, sendo assim, se tiver algum dado inválido o dialog é mantido aberto e exibe as mensagens de erro pro usuário.

    O meu problema é o seguinte. O botão que chama o dialog, faz todo o processo de inicializar o conteúdo do Backing Bean e atualizar os campos da interface, sendo assim, sempre que eu abrir um dialog de cadastro, os campos estarão limpos. Se eu envio os dados e o sistema me retorna algum erro, o dialog exibe o erro corretamente. Então eu clico em cancelar, ou seja, desisti de salvar os dados e de corrigir os erros. Quando eu reabro o dialog, mesmo tendo atualizado a interface e o backing bean, os dados inseridos na tentativa anterior, continuam lá. Isso só ocorre quando o dialog me retorna um erro e eu cancelo sua exibição.

    Tentei sua solução (cleanSubmittedValues) e ao clicar em cancelar, limpar todos os campos da GUI.
    Misteriosamente esse método só funciona corretamente na primeira vez. Se eu tento repetir o processo para gerar mensagem de erro e cancelar o dialog, quando eu abrí-lo de novo os dados digitados continuaram lá.

    Eu debuguei a aplicação, os métodos são chamados corretamente. Nessa segunda repetição o componente vem com sua lista de childrens zerada ( o que não era pra acontecer).

    Parece que misteriosamente o dado continua na interface mesmo sem ter passado pelo binding dele com o bean.

    Já tentei inúmeras soluções e sem sucesso até o momento. Aqui encontrei um problema semelhante:
    http://www.coderanch.com/t/491486/JSF/java/Re-Render-after-ValidationException

    E inclusive estou com um post no fórum do primefaces. Se você tiver alguma idéia, ficarei grato em qualquer ajuda.

    Desde já obrigado!

  80. Rafael Ponte says:

    Olá Herick,

    Pelo visto você já está bem alinhado com a problemática da coisa. De qualquer forma, há uma discussão no #guj sobre o assunto, quem sabe te ajude de alguma maneira: http://guj.com.br/java/239891-jsf-2-problema-com-requiredtrue-no-hinputtext-

    No mais, se o método cleanSubmittedValues() não estiver funcionando talvez o problema seja, até onde posso supor, 1) algum componente do Primefaces possui algum bug que não está de acordo com a spec do JSF2.0 – o antigo componente de calendário dele tinha um bug desse tipo; ou 2) você pode está tendo problemas com composite components do Facelets, como levantado pelo Danilo Magrini aqui: https://gist.github.com/945737

    Talvez você possa levar sua dúvida à lista do #javasf. Provavelmente alguém com mais experiência com os componentes do Primefaces poderá te ajudar.

    Um abraço.

  81. Marcio says:

    Rafael, tenho um exemplo bem parecido com o que você apresentou aqui neste post, e estou com o seguinte problema, se você tiver uma idéia, agradeço.

    Estou usando o sistema normalmente, e quando aciono o botão voltar do navegador (back button) o sistema volta para a primeira tela, a tela de login. Ele não guarda as view que eu naveguei. Tem alguma configuração para isso?

    Grato.

  82. Bispo says:

    Olá Rafael,
    Bem estou precisando chamar uma função javascript no bean. Existe essa possibilidade?

    Abraço!

  83. Cícero says:

    Olá,
    Encontrei algo usando JSP, mas muito arcaico.
    Opa, parabéns pelos seus post
    show de bola

    Abraço!

  84. find more says:

    Thank you for any other fantastic post. Where else may anyone get that type of information in such an ideal manner of writing? I have a presentation subsequent week, and I am on the look for such information.

  85. Ricardo says:

    Olá Rafael,

    Estou utilizando no meu projeto essa estratégia de navegação por estados, mas surgiu uma dúvida quando meu objeto tem coleções tipo A possui coleção de B,no bloco de edição de A, eu trago os daos de A e sua lista de B’s, agora suponha que eu queira inserir um B ou modificar um B especifco dessa lista, se a cada alteração oi inclusão de B eu já refletir isso na base e buscar novamente no banco o registro A com sua coleção de B e dar refresh na view posso ferrar com a aplicação? Tens alguma sugestão para manipulação deste tipo de relacionamento 1: n quando se trabalha com navegação por estados?

  86. Rafael Ponte says:

    Oi Ricardo,

    Não entendi bem sua dúvida, logo, vou levar em consideração somente sua última pergunta. Acredito que sua dúvida esteja relacionada a mestre-detalhe, certo?

    Normalmente para estes casos você pode carregar a entidade principal e seus relacionamentos e coloca-los num escopo mais longo que request, como @ViewScoped, e só no final você envia todos os dados para o banco de dados.

    Em alguns casos mais críticos talvez seja necessário ficar consultando o relacionamento a cada request.

    Seria esta sua dúvida?

  87. Ricardo Johannsen says:

    Boa noite Rafael.

    Sim eram essas as dúvidas, aprimeira pergunta era sobre esses casos criticos que vc tbm respondeu,obrigado.

    Eu já trabalho mestre detalhe dessa forma que vc sugeriu, o que tá me tirando do sério é o sistema que tou desenvolvendo,não é um simples mestre detalhe,tem pra mais de 15 detalhes,tou bolando uma forma de exibir isso na tela e trabalhar com isso,é um sistema de processos, processo é o mestre e ele tem seus detalhes: andamentos,decisões,acórdãos,documentos,julgamentos…
    não queria carregar tudo de uma vez.

    Eu pensei em fazer mais ou menos assim,na listagem dos processos eu teria dois commandLinks um que vai para os dados do processo e outro que vai para a pagina do processo com os detalhes.

    Na pagina do detalhes eu teria uma estrutura de árvore,onde cada nó,representaria um detalhe:

    Processo
    |_andamentos
    |_julgamentos
    |_documentos

    quando eu clicasse em um nó, eu carregaria só o processo com aquele relacionamento,por exemplo se eu clicar em andamentos eu trago só o processo com os andamentos,se clicar em julgamentos trago apenas o processo com os julgamentos e assim por diante e acho que vou cair na dúvida da primeira questão porque toda vez que eu inserir um andamento no processo vou ter que recuperar essa relação, existe uma forma melhor de lidar com esse tipo de relacionamento com muitos detalhes? ou recuperar tudo na hora de exibir e ao salvar,enviar tudo pro banco continua sendo melhor?

  88. Rafael Ponte says:

    Oi Ricardo,

    Acredito que decidir sobre a solução está muito ligado a usabilidade e interação da tela. Decida a usabilidade primeiro que fica mais simples decidir como você vai carregar a entidade principal.

    Mas no geral eu tentaria seguir a solução mais simples: carregaria a entidade completa com todos seus relacionamentos e jogaria no escopo view, assim eu poderia ir modificando a entidade em memória e somente no final pediria para o EntityManagerpara persisti-la.

9 Pings/Trackbacks for "Utilizando AJAX com JSF de maneira eficiente"
  1. [...] web, temos o costume de sempre pensar em navegação entre páginas. O Rafael Ponte apresentou uma alternativa no mínimo interessante para JSF utilizando RichFaces + [...]

  2. [...] incrível como depois do post Utilizando AJAX com JSF de maneira eficiente muitos desenvolvedores tem utilizado o exemplo básico do post -que nada mais era do que uma prova [...]

  3. [...] Ext4JSF por aí? Além do mais será mais rápido e prático implementar interfaces do tipo “on a single page interface web application“, já que todo o processamento da interface gráfica ficará no lado [...]

  4. [...] as aplicações web estão caminhando para uma GUI mais rica e versátil, e ao abrir mão da “velha escola” conseguimos contornar os problemas citados acima facilmente, como também obter inúmeras [...]

  5. [...] Um dos grandes problemas para quem está começando com JSF e componentes AJAX é a maneira como estes desenvolvedores subutilizam os recursos AJAX do framework e dos componentes. Sendo, vale a pena estudar e adotar uma abordagem mais eficiente para isso, uma abordagem com foco em navegação orientada a estados. [...]

  6. [...] · Nenhum Comentário Olá pessoal, o artigo do dia é este: Utilizando ajax com JSF de maneira eficiente. Escrito por Rafael Ponte, explica muito bem conceitos de ajax com [...]

  7. [...] sobre o assunto, encontrei o post  Utilizando AJAX com JSF de maneira eficiente, onde podemos observer um código “HTML“. O curioso é que a única tag HTML utilizada [...]

  8. [...] de Campos 2.Paradigma Ajax com JSF 3.Conversores com Entidades 4.Entendendo Redirect X Forward 5.Controlando Nomeação dos GUI [...]

  9. [...] tantos benefícios dessa abordagem apareceram alguns problemas que também não estávamos acostumados a lidar, como saber o que [...]

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>