Quando usar action ou actionListener com JSF
Sabe aquela dúvida comum: action vs actionListener? Entenda a diferença entre os dois e saiba qual o melhor para sua aplicação JSF
Basicamente temos duas formas de executar uma ação no managed bean após clicar em um botão ou link com JSF. Podemos passar uma EL (Expression Language) para o atributo action
ou para o atributo actionListener
do componente. Apesar de ambos os atributos invocarem um método no managed bean, eles possuem um diferença sútil que costuma levar a pergunta: quando e qual devo usar?
Não é difícil decidir qual usar. Para isso precisamos antes entender a motivação por trás de cada um e suas peculiaridades.
Action
Você deveria usar uma action
se sua intenção é executar uma lógica de negócio ou navegar entre páginas. O método da action
pode retornar uma String
indicando a regra de navegação. Por exemplo, para executar uma lógica de negócio que grava um produto no banco de dados teríamos algo como:
<h:commandButton value="Grava" action="#{produtoBean.salva}" />
E no managed bean teríamos este método:
public String salva() {
this.dao.adiciona(this.produto);
return "listagem";
}
Repare que após gravar o produto o managed bean executa uma regra de navegação para que o usuário seja redirecionado para a página de listagem de produtos. Esta regra de navegação é conhecida como outcome. Se o método retorna null
ou possui retorno void
, o usuário é mantido na mesma página e o JSF reaproveita a mesma árvore de componentes. O mesmo pode ser obtido se uma String
vazia é retornada ou o outcome retornado leve para a mesma página, nesse caso a diferença é que uma nova árvore de componentes é criada.
Podemos ir mais longe e passar argumentos para o método da action
na EL (desde a EL 2.2), como a seguir:
<h:commandButton value="Exclui" action="#{produtoBean.remove(produto)}" />
No managed bean temos:
public void remove(Produto produto) {
this.dao.remove(produto);
}
Se quisermos apenas navegar entre páginas sem executar qualquer lógica no managed bean, basta passar o outcome diretamente no atributo action
em vez de uma EL, como no código abaixo:
<h:commandLink value="Novo" action="novo_produto" />
ActionListener
Você deveria usar uma actionListener
se o que você quer fazer é executar uma lógica relacionada a view ou disparar uma ação antes de uma lógica de negócio. A lógica invocada por uma actionListener
está mais ligada a detalhes da tela do que puramente regras de negócio. Para usá-lo em uma h:commandButton
bastaria termos o código a seguir:
<h:commandButton value="Limpar formulário" actionListener="#{produtoBean.limpar}" />
O managed bean teria um método limpar
que receberia como argumento um ActionEvent
:
import javax.faces.event.ActionEvent;
// ...
public void limpar(ActionEvent event) {
UIForm form = event.getComponent().getParent();
facesUtils.cleanSubmittedValues(form);
}
Como podemos ver, o método retorna void
, dessa forma o usuário continua na mesma página após o fim da requisição. Com actionListener
não é possível navegar para outra página.
Assim como na action
, nós também podemos passar argumentos para o método de uma actionListener
. Os exemplos a seguir são válidos:
<h:commandButton ... actionListener="#{bean.processa()}" />
<h:commandButton ... actionListener="#{bean.processa(arg1)}" />
<h:commandButton ... actionListener="#{bean.processa(arg1, arg2)}" />
Os parênteses são importantes quando queremos que o método não receba nenhum argumento, nem mesmo uma ActionEvent
. Sem os parênteses o JSF ainda esperaria a ActionEvent
.
Uma actionListener
também pode ser registrada em um componente através de tags especializadas. Uma tag muito utilizado na maioria dos projetos é a tag f:setPropertyActionListener
, ela preenche informações no managed bean antes de disparar uma lógica de negócio. Outra maneira menos convencional é através da tag f:actionListener
na qual aponta para uma classe que implementa a interface javax.faces.event.ActionListener
.
A ordem importa
É importante ter ciência que as actionListener
's são invocadas antes da action
na mesma ordem em que elas são registradas no componente. O exemplo a seguir pode ajudar no entendimento:
<h:commandButton ... actionListener="#{bean.listener1}" action="#{bean.submit}">
<f:actionListener type="br.com.triadworks.MyActionListener" />
<f:setPropertyActionListener target="#{bean.valor}" value="xpto" />
</h:commandButton>
Dessa forma, o exemplo acima invocará os métodos na seguinte ordem:
- primeiramente o método
Bean#listener1()
; - logo em seguida a
MyActionListener#processAction()
; - depois o
Bean#setValor()
; - e por fim
Bean#submit()
, que é nossaaction
;
Não é à toa que normalmente usamos a tag f:setPropertyActionListener
para definir um atributo no managed bean antes de executar uma lógica de negócio ou redirecionar o usuário para outra página.
Exceções
A actionListener
suporta uma exceção especial, a AbortProcessingException
. Se esta exceção é lançada de um método de uma actionListener
o JSF irá parar o processamento e pular para última fase do ciclo de vida. Nenhum erro será exibido na tela, pois o JSF irá capturar a exceção e apenas logará o erro.
Por outro lado, a action
exibe o erro para usuário independente da exceção lançada pelo método.
Então, qual devo usar?
No geral é possível usar qualquer uma das abordagens para invocar um método no managed bean. Mas entender a motivação de cada uma é importante para tirarmos melhor proveito do JSF e de seus recursos. Esta dúvida e outras são discutidas durante o curso de JSF 2 com Spring da TriadWorks.
Devemos usar a action
para maioria dos casos, já que ela é a responsável por executar regras de negócio na aplicação. Além disso, ela é quem decide para onde navegar entre as páginas do sistema. Mesmo quando trabalhamos com AJAX, onde normalmente não existe navegação entre páginas, ainda assim podemos usar uma action
que possui retorno void
, por exemplo.
Só deveríamos usar uma actionListener
se nossa lógica for relacionada a view, como limpar um formulário, bloquear ou esconder componentes etc ou se precisarmos preparar o managed bean antes de invocar alguma lógica de negócio.
E você, o que tem usado para disparar lógicas de negócio nas suas aplicações JSF, action
ou actionListener
?
You might also be interested in these articles...
Desenvolvedor e instrutor na TriadWorks