Diferencias entre acción y acción

¿Cuál es la diferencia entre action y actionListener , y cuándo debería usar action versus actionListener ?

actionListener

Use actionListener si quiere tener un gancho antes de que se ejecute la acción comercial real, por ejemplo, para iniciar sesión, y / o establecer una propiedad adicional (por ), y / o tener acceso al componente que invocó el acción (que está disponible por el argumento ActionEvent ). Por lo tanto, solo para fines de preparación antes de que se invoca la acción comercial real.

El método actionListener tiene por defecto la siguiente firma:

 import javax.faces.event.ActionEvent; // ... public void actionListener(ActionEvent event) { // ... } 

Y se supone que debe declararse de la siguiente manera, sin ningún paréntesis de método:

  

Tenga en cuenta que no puede pasar argumentos adicionales por EL 2.2. Sin embargo, puede anular el argumento ActionEvent pasando y especificando argumento (s) personalizado (s). Los siguientes ejemplos son válidos:

    
 public void methodWithoutArguments() {} public void methodWithOneArgument(Object arg1) {} public void methodWithTwoArguments(Object arg1, Object arg2) {} 

Tenga en cuenta la importancia de los paréntesis en la expresión de método sin argumentos. Si estuvieran ausentes, JSF todavía esperaría un método con el argumento ActionEvent .

Si tiene EL 2.2+, puede declarar métodos de escucha de acción múltiple a través de .

     
 public void actionListener1(ActionEvent event) {} public void actionListener2() {} public void actionListener3() {} 

Tenga en cuenta la importancia de los paréntesis en el atributo de binding . Si estuvieran ausentes, EL arrojaría confusamente una javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean , porque el atributo de binding se interpreta por defecto como una expresión de valor, no como una expresión de método. Agregar el paréntesis de estilo EL 2.2+ de forma transparente convierte una expresión de valor en una expresión de método. Ver también ao ¿Por qué puedo vincular a un método arbitrario si no es compatible con JSF?


acción

Use action si desea ejecutar una acción comercial y, si es necesario, manipular la navegación. El método de action puede (por lo tanto, no debe) devolver una String que se utilizará como resultado de caso de navegación (la vista de destino). Un valor de retorno null o void le permitirá volver a la misma página y mantener vivo el scope de la vista actual. Un valor de retorno de una cadena vacía o la misma ID de vista también volverá a la misma página, pero recreará el scope de la vista y destruirá, por lo tanto, los beans de la vista actualmente activa y, si corresponde, los volverá a crear.

El método de action puede ser cualquier MethodExpression válido, también aquellos que usan argumentos EL 2.2 como los siguientes:

  

Con este método:

 public void edit(Item item) { // ... } 

Tenga en cuenta que cuando su método de acción solo devuelve una cadena, también puede especificar exactamente esa cadena en el atributo de action . Por lo tanto, esto es totalmente torpe:

  

Con este método sin sentido devolviendo una cadena codificada:

 public String goToNextpage() { return "nextpage"; } 

En su lugar, simplemente ponga esa cadena codificada directamente en el atributo:

  

Tenga en cuenta que esto a su vez indica un mal diseño: navegando por POST. Esto no es amigable ni de usuario. Todo esto se explica en ¿ Cuándo debería usar h: outputLink en lugar de h: commandLink? y se supone que debe resolverse como

  

Ver también ¿Cómo navegar en JSF? Cómo hacer que la URL refleje la página actual (y no la anterior) .


f: oyente ajax

Desde JSF 2.x hay una tercera vía, el .

    

El método ajaxListener tiene por defecto la siguiente firma:

 import javax.faces.event.AjaxBehaviorEvent; // ... public void ajaxListener(AjaxBehaviorEvent event) { // ... } 

En Mojarra, el argumento AjaxBehaviorEvent es opcional, debajo funciona como bueno.

 public void ajaxListener() { // ... } 

Pero en MyFaces arrojaría una MethodNotFoundException . A continuación funciona en ambas implementaciones JSF cuando quiere omitir el argumento.

    

Los oyentes Ajax no son realmente útiles en los componentes del comando. Son más útiles en la entrada y seleccionan componentes / . En los componentes de comando, solo adhiérase a action y / o actionListener para mayor claridad y mejor código de auto-documentación. Además, al igual que actionListener , el f:ajax listener no admite la devolución de un resultado de navegación.

    

Para obtener una explicación sobre los atributos de execute y render , diríjase a Understanding PrimeFaces process / update y JSF f: ajax execute / render attributes .


Orden de invocación

Los actionListener s siempre se invocan antes de la action en el mismo orden en que se declararon en la vista y se adjuntaron al componente. El f:ajax listener siempre se invoca antes de cualquier oyente de acción. Entonces, el siguiente ejemplo:

       

Invocará los métodos en el siguiente orden:

  1. Bean#ajaxListener()
  2. Bean#actionListener()
  3. ActionListenerType#processAction()
  4. Bean#actionListenerBinding()
  5. Bean#setProperty()
  6. Bean#action()

Manejo de excepciones

actionListener admite una excepción especial: AbortProcessingException . Si esta excepción se produce desde un método actionListener , JSF omitirá los detectores de acción restantes y el método de acción y procederá a presentar la respuesta directamente. No verá una página de error / excepción, JSF sin embargo lo registrará. Esto también se realizará implícitamente cuando se lanza cualquier otra excepción desde un actionListener . Por lo tanto, si tiene la intención de bloquear la página por una página de error como resultado de una excepción empresarial, entonces definitivamente debe realizar el trabajo en el método de action .

Si la única razón para usar un actionListener es tener un método void volviendo a la misma página, entonces esa es una mala. Los métodos de action también pueden volverse void , al contrario de lo que algunos IDEs te permiten creer a través de la validación de EL. Tenga en cuenta que los ejemplos de escaparate de PrimeFaces están llenos de este tipo de actionListener s over all place. Esto de hecho está mal. No use esto como una excusa para hacer eso usted mismo.

Sin embargo, en las solicitudes ajax, se necesita un manejador de excepción especial. Esto es independientemente de si usa el atributo de listener de o no. Para una explicación y un ejemplo, dirígete al manejo de excepciones en solicitudes JSF ajax .

Como BalusC indicó, actionListener por defecto absorbe excepciones, pero en JSF 2.0 hay un poco más de esto. A saber, no solo traga y registra, sino que realmente publica la excepción.

Esto sucede a través de una llamada como esta:

 context.getApplication().publishEvent(context, ExceptionQueuedEvent.class, new ExceptionQueuedEventContext(context, exception, source, phaseId) ); 

El detector predeterminado para este evento es el ExceptionHandler que para Mojarra se establece en com.sun.faces.context.ExceptionHandlerImpl . Esta implementación básicamente volverá a lanzar cualquier excepción, excepto cuando se trate de una AbortProcessingException, que se registra. ActionListeners envuelve la excepción que arroja el código del cliente en una AbortProcessingException que explica por qué estos siempre se registran.

Este ExceptionHandler se puede reemplazar, sin embargo, en faces-config.xml con una implementación personalizada:

  com.foo.myExceptionHandler  

En lugar de escuchar globalmente, un solo frijol también puede escuchar estos eventos. La siguiente es una prueba de concepto de esto:

 @ManagedBean @RequestScoped public class MyBean { public void actionMethod(ActionEvent event) { FacesContext.getCurrentInstance().getApplication().subscribeToEvent(ExceptionQueuedEvent.class, new SystemEventListener() { @Override public void processEvent(SystemEvent event) throws AbortProcessingException { ExceptionQueuedEventContext content = (ExceptionQueuedEventContext)event.getSource(); throw new RuntimeException(content.getException()); } @Override public boolean isListenerForSource(Object source) { return true; } }); throw new RuntimeException("test"); } } 

(Nota, esta no es la forma en que uno normalmente debería codificar oyentes, ¡esto es solo para fines de demostración!)

Llamar esto desde un Facelet como este:

        

Se generará una página de error.

ActionListener se activa primero, con una opción para modificar la respuesta, antes de que se llame a Action y determine la ubicación de la página siguiente.

Si tiene varios botones en la misma página que deberían ir al mismo lugar pero hacer cosas ligeramente diferentes, puede usar la misma Acción para cada botón, pero use un ActionListener diferente para manejar una funcionalidad ligeramente diferente.

Aquí hay un enlace que describe la relación:

http://www.java-samples.com/showtutorial.php?tutorialid=605