Nova versão do JSF 2 não dispara o FORWARD na navegação das paginas XHTML [RESOLVIDO]

estou terminando a parte de orçamentos no site, assim q terminar isso, vou dar uma olhada com mais calma na sua sugestão de usar filter + phase, não é q eu fiz a minha opção, eu acho q ontem meio na preça perto das 6 da tarde, eu não consegui compreender direito, assim q eu folgar aqui vou dar uma lida novamente, e volto a testar e postar os resultados aqui

Olá amigos,

Vou postar minha dúvida aqui apesar de não ter relação específica. É um caso de redirect no JSF 2.

Tenho uma formulário de registro (com escopo view pois tenho combos aninhadas nele) e ao aplicar a ação Save, mostro uma janela de diálogo com a informação de sucesso.

Começa aí o meu problema. Se fosse somente para mostrar na tela eu utilizaria o h:messages ou p:messages ou p:growl mas eu preciso, a finalizar a gravação do usuário, redirecionar para a página de login. Neste caso, se eu utilizar o recurso do jsf 2 para mostrar as mensagens e renderizar automaticamente o p:dialog (not empty facescontext.maximumSeverity), mostra normal a menos que eu redirecione a página. Se eu inserir no managedBean o redirecionamento, a mensagem “é engolida”. Eu li alguns posts em que o pessoal comenta sobre recuperar as mensagens por meio de phaselistener mas confesso que tou perdido nesse assunto. Não entendi direito e gostaria de saber se há outra solução senão esta.

O que eu fiz e que não gostaria de ter feito (pois é um retrabalho em cima do que já é feito pelo JSF) é implementar um controle por meio de atributo, por exemplo, atributo exibeDialog. Neste caso eu abro o p:dialog de acordo com o valor do atributo boolean. Só que este controle que fiz já identifiquei que, se estiver em um escopo de sessão, a todo momento teria que “limpar” o atributo exibeDialog para não ficar mostrando a janela de diálogo entre a navegação das páginas.

Olha, pesquisei muito sobre este esquema de mostrar uma janela de diálogo. Mostrar é muito tranquilo. O problema é mostrar e poder redirecionar para outra página sem que o JSF “engula” a mensagem.

Ah, outro detalhe, o meu redirecionamento no managedBean eu estou realizando pelo .redirect(pagina) do próprio faces mesmo. Também se utilizar o return "paginaX.jsf?redirect=true, ocorre o mesmo. A mensagem é “engolida”.

Sds,
Rodrig Bortolon

[quote=rbortolon]Olá amigos,

Vou postar minha dúvida aqui apesar de não ter relação específica. É um caso de redirect no JSF 2.

Tenho uma formulário de registro (com escopo view pois tenho combos aninhadas nele) e ao aplicar a ação Save, mostro uma janela de diálogo com a informação de sucesso.

Começa aí o meu problema. Se fosse somente para mostrar na tela eu utilizaria o h:messages ou p:messages ou p:growl mas eu preciso, a finalizar a gravação do usuário, redirecionar para a página de login. Neste caso, se eu utilizar o recurso do jsf 2 para mostrar as mensagens e renderizar automaticamente o p:dialog (not empty facescontext.maximumSeverity), mostra normal a menos que eu redirecione a página. Se eu inserir no managedBean o redirecionamento, a mensagem “é engolida”. Eu li alguns posts em que o pessoal comenta sobre recuperar as mensagens por meio de phaselistener mas confesso que tou perdido nesse assunto. Não entendi direito e gostaria de saber se há outra solução senão esta.

O que eu fiz e que não gostaria de ter feito (pois é um retrabalho em cima do que já é feito pelo JSF) é implementar um controle por meio de atributo, por exemplo, atributo exibeDialog. Neste caso eu abro o p:dialog de acordo com o valor do atributo boolean. Só que este controle que fiz já identifiquei que, se estiver em um escopo de sessão, a todo momento teria que “limpar” o atributo exibeDialog para não ficar mostrando a janela de diálogo entre a navegação das páginas.

Olha, pesquisei muito sobre este esquema de mostrar uma janela de diálogo. Mostrar é muito tranquilo. O problema é mostrar e poder redirecionar para outra página sem que o JSF “engula” a mensagem.

Ah, outro detalhe, o meu redirecionamento no managedBean eu estou realizando pelo .redirect(pagina) do próprio faces mesmo. Também se utilizar o return "paginaX.jsf?redirect=true, ocorre o mesmo. A mensagem é “engolida”.

Sds,
Rodrig Bortolon[/quote]

As mensagens não são engolidas não…elas simplesmente ficam no escopo request e por isso são perdidas quando ha um redirecionamento(é criado outro request). Por isso que, conceitualmente vc não pode fazer essa operação.

Olá Fernando,

Pois é, lembro que li um post aqui que o Rafael Ponte comentou justamente isso. Sobre o escopo de request e mensagens. Mas e no meu caso e em outros em que o managedBean tem que estar com escopo de view ou session ?

Não há outra solução ?

Outro detalhe sobre CRUD e escopo do jsf. Na internet vejo vários exemplos de como utilizar CRUD no JSF onde é demonstrado tudo num só xhtml. Ou seja, nele há o datatable e um p:dialog. Até ai tudo bem pois no mesmo bean é tranquilo de tratar os dados e com poucos atributos. Entendo que é só um exemplo para demonstração. Mas e um exemplo como vou citar abaixo ?

No meu formulário de Estabelecimento (cadastro) tenho que ter vários atributos inclusive outra aba para fotos. Ou seja, não posso manter tudo isso num p:dialog. Neste caso vou separar em outra página. Uma é a página de pesquisa e outra é a página de cadastro de estabelecimentos. Portanto, cabe aí o uso de um escopo de session (me corriga se estiver errado). E é justamente neste ponto que quero chegar. Não vi sequer um exemplo em forums e na internet sobre este caso de CRUD com separação por páginas. Você já viu algum exemplo ou pode me passar algum link sobre ? Eu já realizei essa implementação no meu sistema(como citei com escopo de sessão) porém gostaria de visualizar exemplos de outras pessoas e trocar idéias sobre esse ponto específico.

Sds,
Rodrigo

[quote]Pois é, lembro que li um post aqui que o Rafael Ponte comentou justamente isso. Sobre o escopo de request e mensagens. Mas e no meu caso e em outros em que o managedBean tem que estar com escopo de view ou session ?
Não há outra solução ? [/quote]
Não…as mensagens não tem nenhuma relação com o managedBeans…no jsf não tem como declarar escopo das mensagens!!
Conceitualmente elas estão no request…pq não faz sentido estar na sessão.
Vc pode manualmente colocar suas mensagens na sessão e imprimi-las na paginas…mas dai vc acaba refazendo o controle.
O mais indicado é não usa redirect…
Pq vc ta usando redirect?

[quote=FernandoFranzini][quote]Pois é, lembro que li um post aqui que o Rafael Ponte comentou justamente isso. Sobre o escopo de request e mensagens. Mas e no meu caso e em outros em que o managedBean tem que estar com escopo de view ou session ?
Não há outra solução ? [/quote]
Não…as mensagens não tem nenhuma relação com o managedBeans…no jsf não tem como declarar escopo das mensagens!!
Conceitualmente elas estão no request…pq não faz sentido estar na sessão.
Vc pode manualmente colocar suas mensagens na sessão e imprimi-las na paginas…mas dai vc acaba refazendo o controle.
O mais indicado é não usa redirect…
Pq vc ta usando redirect?[/quote]

Fernando, não quis dizer que mensagens tem relação com o escopo. Eu quis mencionar o que vc justamente comentou. Que se o escopo do managedBean está diferente de request (que no meu caso é session), ocorre este problema.

Não estamos falando aqui de escopo de mensagens e sim do escopo dos managedBean’s. Até ai ok.

O caso de implementar mensagens customizadas é justamente o que eu fiz e que acho uma “invenção da roda” sendo que o jsf deveria fazer isso.

Imagine só no que citei onde há um crud com tela de pesquisa (onde há o datatable com a lista de estabelecimentos) e quando o usuário clica em um registro, o sistema redireciona (olha só o redirect aqui) para outra página. Na página de alteração de dados do estabelecimento, eu quero que o sistema salve os dados e após, redirecione para a página de pesquisa novamente. Só que caímos no problema que citei. Se eu mostrar a mensagem em um p:messages e existir o redirect, o usuário não vai nem ver. Ou seja, para isso preciso de uma janela modal (p:dialog) onde o usuário receba a mensagem “Estab. cadastrado com sucesso” e depois de clicado no botão ok, ocorra o redirect. Só que se eu fizer via facesmessage mostrando nesta janela modal e com o redirect no managedbean, essa mensagem não é mostrada pelo motivo que comentamos (escopo request).

Hoje a noite vou realizar 2 tentativas.

  1. Uma é realizar a utilização do facesMessage para mostrar a mensagem porém o redirect vou tentar inserir direto no evento do botão ok do p:dialog;
  2. Utilizar a exibição personalizada de mensagens de acordo com o atributo que criei exibeDialog (o porém desta alternativa é o controle que é muito trabalhoso).

Sds,
Rodrigo

Vou perguntar de novo…
Pq vc ta usando redirect ou invés de usar o padrão forward?

rbortolon, pelo q to entendendo do seu problema, simplesmente nao tem como fazer, (exibir uma mensagem em uma pagina, e em seguida mudar de pagina), é normal a mensagem sumir, vc saiu da pagina que ela foi exibida… e usar esse atributo de controle (q diz se foi salvo com sucesso ou não) para exibir a mensagem na pagina de pesquisa invés de exibir na pagina de cadastro, na minha opinião nao tem nd de mais, e é correto, é uma lógica de programação q vc usou pra resolver um problema… eu acho q teria feito dessa forma tbem se precisasse de algo assim…

Eu ja acho que vc não optou pela melhor opção, uma vez que não existe justificativa arquitetural que viabilize seu uso de redirect!
Coloque redirect é use o mecanismo de mensagem do JSF.
redirect é ruim é todos os sentidos como ja descritos aqui…

Ola amigos,

Fernando, o uso do redirect eu preciso utilizar pois minha url não pode continuar a mesma.

Exemplo:

  1. page1?faces-redirect=true" value="Page1" />

Ou o que eu utilizei com um método de navegação onde eu redireciono para pagina especifica

  1. FacesContext.getCurrentInstance().getExternalContext().redirect(pageName.toString());

Se eu usar o forward, ok, eu entendo o que quis dizer mas no caso por exemplo de minha lista de estabelecimentos onde eu clico em um registro e eu quero q apareça na URL a injeção dos parâmetros, eu utilizeo o redirect como no exemplo 1. No managed Bean eu recebo os dados da classe converter e a url ficará com o parametro que preciso.

Mas o que realmente estava com problemas era na questão de mostrar a mensagem e logo após redirecionar ao clicar no botão da mensagem. Como informei anteriormente, tive que criar uma lógica no mb seguindo o exemplo contido no link abaixo. Está funcionando ok.

Se alguém precisar, taí !

Obrigado a todos,
Rodrigo Bortolon

Parabens pela discussão rica em detalhes quanto a implementação do filtro + phaseListeners. Muito bom!

Cara eu testei aqui e o Filtro é disparado SEMPRE. O JSF faz as requisicoes do tipo post normalmente e no forward para uma outra pagina o filtro é acionado.

Excelente discussão. Como o ThiagoInGuj já mencionou, muito rica. Parabéns ao “FernandoFranzini” e ao “cleiton herrmann”. Só voltando aos pormenores referentes à configuração de regras de navegação com o faces-config, existe possibilidade de se definir essas regras sem ter a necessidade de se criar este arquivo de configuração (nem mesmo para definir o lifecycle do phaselistener)?

[quote]Phase listerner de RENDER_RESPONSE é executado somente depois da ação do bean…#{bean.acao}!!!
Se caso o usuario não estiver logado ou expirar a sessão dele…se ele clickar no botão da GUI o sistema vai executar a ação do botão e depois disso de sera enviado a pagina de login. E nós não queremos isso né…
[/quote]

Não precisa implementar dois PhaseListener, basta invocar o método FacesContext.getCurrentInstance().responseComplete() na chamada do método beforePhase(PhaseEvent event), deste modo a execução da ação é aborta e o método não é executado.

Segue abaixo o exemplo:

[code]abstract class Authorization {

/**
 * Paginas que nao necessitam que o usuario esteja autenticado para
 * exibicao.
 */
private static final String[] pages = new String[] { "accessdenied.xhtml" };

protected void checkBeforePhase() {
	FacesContext fc = FacesContext.getCurrentInstance();
	HttpServletResponse response = (HttpServletResponse) fc.getExternalContext().getResponse();
	HttpServletRequest request = (HttpServletRequest) fc.getExternalContext().getRequest();

	if (requireAuthorization(request.getPathInfo())) {
		return;
	}

	LoginMB loginMB = (LoginMB) request.getSession(true).getAttribute("loginMB");
	if (ParamUtil.isNull(loginMB)) {
		try {
			request.getSession(true);
			response.sendRedirect(request.getContextPath() + "/faces/pages/error/accessdenied.xhtml");
			/*
			 * Aborta a requisicao.
			 */
			fc.responseComplete();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

/**
 * Verifica se a pagina solicitada necessida que o usuario esteja
 * autenticado na aplicacao.
 * 
 * @param path
 *            Url da pagina solicitada.
 * @return <code>true</code> necessida de autenticacao, <code>false</code>
 *         caso contrario.
 */
private boolean requireAuthorization(String path) {
	for (String s : pages) {
		if (path.contains(s)) {
			return false;
		}
	}
	return true;
}

}

public class RestoreViewPhase extends Authorization implements PhaseListener {

@Override
public void afterPhase(PhaseEvent event) {
	
}

@Override
public void beforePhase(PhaseEvent event) {
	checkBeforePhase();
}

@Override
public PhaseId getPhaseId() {
	return PhaseId.RESTORE_VIEW;
}

}[/code]