Les différences entre l'action et actionListener
-
29-09-2019 - |
Question
Quelle est la différence entre action
et actionListener
, et quand dois-je utiliser action
contre actionListener
?
La solution
actionListener
Utilisez actionListener
si vous voulez avoir un crochet avant la vraie action entreprise s'exécuter, par exemple pour se connecter, et / ou pour une propriété supplémentaire (par <f:setPropertyActionListener>
), et / ou d'avoir accès au composant qui a invoqué l'action (qui est disponible par ActionEvent
argument). Ainsi, uniquement pour la préparation des fins avant que l'action réelle des entreprises s'invoqué.
La méthode de actionListener
a par défaut la signature suivante:
import javax.faces.event.ActionEvent;
// ...
public void actionListener(ActionEvent event) {
// ...
}
Et il est censé être déclaré comme suit, sans parenthèses méthode:
<h:commandXxx ... actionListener="#{bean.actionListener}" />
Notez que vous ne pouvez pas passer supplémentaires arguments avancés par EL 2.2. Vous pouvez cependant passer outre l'argument ActionEvent
tout à fait en passant et en spécifiant l'argument personnalisé (s). Les exemples suivants sont valables:
<h:commandXxx ... actionListener="#{bean.methodWithoutArguments()}" />
<h:commandXxx ... actionListener="#{bean.methodWithOneArgument(arg1)}" />
<h:commandXxx ... actionListener="#{bean.methodWithTwoArguments(arg1, arg2)}" />
public void methodWithoutArguments() {}
public void methodWithOneArgument(Object arg1) {}
public void methodWithTwoArguments(Object arg1, Object arg2) {}
Notez l'importance des parenthèses dans l'expression de la méthode argumentless. S'ils étaient absents, JSF attendre encore une méthode avec l'argument de ActionEvent
.
Si vous êtes sur EL 2.2+, vous pouvez déclarer plusieurs méthodes d'écouteur d'action via <f:actionListener binding>
.
<h:commandXxx ... actionListener="#{bean.actionListener1}">
<f:actionListener binding="#{bean.actionListener2()}" />
<f:actionListener binding="#{bean.actionListener3()}" />
</h:commandXxx>
public void actionListener1(ActionEvent event) {}
public void actionListener2() {}
public void actionListener3() {}
Notez l'importance des parenthèses dans l'attribut binding
. S'ils étaient absents, EL serait de prêter à confusion jeter un javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean
, parce que l'attribut binding
est par défaut interprété comme une expression de valeur, et non comme une expression de la méthode. Ajout des parenthèses de style de EL se transparente une expression de valeur dans une expression de la méthode. Voir aussi A.O. Pourquoi est-ce Je capable de se lier
Action
Utilisez action
si vous voulez exécuter une action commerciale et si nécessaire poignée de navigation. La méthode peut action
(donc, ne doit pas) retourner un String
qui sera utilisé comme résultat de cas de navigation (la vue cible). Une valeur de retour de null
ou void
va le laisser revenir à la même page et garder la vue actuelle portée en vie. Une valeur de retour d'une chaîne vide ou le même ID de vue également revenir à la même page, mais recréer la portée de vue et ainsi détruire toute vue active scope haricots et, le cas échéant, de les recréer.
La méthode de action
peut être tout valide MethodExpression
, aussi ceux qui utilisent EL 2,2 arguments comme ci-dessous:
<h:commandXxx value="submit" action="#{bean.edit(item)}" />
Avec cette méthode:
public void edit(Item item) {
// ...
}
Notez que lorsque votre méthode d'action retourne uniquement une chaîne, vous pouvez aussi simplement spécifier exactement cette chaîne dans l'attribut action
. Ainsi, ce qui est totalement maladroit:
<h:commandLink value="Go to next page" action="#{bean.goToNextpage}" />
Avec cette méthode insensée retournant une chaîne hardcoded:
public String goToNextpage() {
return "nextpage";
}
Au lieu de cela, il suffit de mettre cette chaîne directement dans l'attribut hardcoded:
<h:commandLink value="Go to next page" action="nextpage" />
S'il vous plaît noter que ce à son tour indique une mauvaise conception: la navigation par POST. Ce n'est pas utilisateur ni SEO friendly. Tout cela est expliqué dans Quand dois-je utiliser h: outputLink au lieu de h: commandLink et est censé être résolu comme
<h:link value="Go to next page" outcome="nextpage" />
Voir aussi Comment naviguer dans JSF? Comment URL faire réfléchir la page en cours (et non précédent) .
f: ajax auditeur
Depuis JSF 2.x, il y a une troisième voie, la <f:ajax listener>
.
<h:commandXxx ...>
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandXxx>
La méthode de ajaxListener
a par défaut la signature suivante:
import javax.faces.event.AjaxBehaviorEvent;
// ...
public void ajaxListener(AjaxBehaviorEvent event) {
// ...
}
Dans Mojarra, l'argument est AjaxBehaviorEvent
en option, ci-dessous fonctionne comme bon.
public void ajaxListener() {
// ...
}
Mais MyFaces, il jetterait un MethodNotFoundException
. Ci-dessous, dans les deux œuvres mises en œuvre JSF lorsque vous voulez omettre l'argument.
<h:commandXxx ...>
<f:ajax execute="@form" listener="#{bean.ajaxListener()}" render="@form" />
</h:commandXxx>
auditeurs Ajax ne sont pas vraiment utiles sur les composants de commande. Ils sont plus utiles sur l'entrée et sélectionnez <h:inputXxx>
/ <h:selectXxx>
composants. Dans les composants de commande, il suffit de coller à action
et / ou actionListener
pour plus de clarté et un meilleur code auto-documenté. De plus, comme actionListener
, le f:ajax listener
ne supporte pas le retour à un résultat de navigation.
<h:commandXxx ... action="#{bean.action}">
<f:ajax execute="@form" render="@form" />
</h:commandXxx>
Pour plus d'explications sur les attributs de execute
et render
, tête comprendre traiter PrimeFaces / mise à jour et JSF f: Ajax exécuter / attributs rendent
pour Invocation
Les actionListener
s sont toujours invoqué avant la action
dans le même ordre que sont été déclarés dans la vue et attaché au composant. Le f:ajax listener
est toujours invoqué avant tout auditeur d'action. Ainsi, l'exemple suivant:
<h:commandButton value="submit" actionListener="#{bean.actionListener}" action="#{bean.action}">
<f:actionListener type="com.example.ActionListenerType" />
<f:actionListener binding="#{bean.actionListenerBinding()}" />
<f:setPropertyActionListener target="#{bean.property}" value="some" />
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandButton>
invoquera les méthodes dans l'ordre suivant:
-
Bean#ajaxListener()
-
Bean#actionListener()
-
ActionListenerType#processAction()
-
Bean#actionListenerBinding()
-
Bean#setProperty()
-
Bean#action()
Gestion des exceptions
Le actionListener
soutient une exception: AbortProcessingException
. Si cette exception est levée à partir d'une méthode de actionListener
, puis JSF sautera écouteurs d'action restants et la méthode d'action et de procéder à rendre une réponse directe. Vous ne verrez pas une page d'erreur / exception, JSF enregistre cependant il. Ce sera aussi implicitement fait à chaque fois une autre exception est lancée à partir d'un actionListener
. Donc, si vous avez l'intention de bloquer la page par une page d'erreur à la suite d'une exception d'affaires, alors vous devriez certainement effectuer le travail dans la méthode action
.
Si la seule raison d'utiliser un actionListener
est d'avoir une méthode de void
revenir à la même page, alors c'est une mauvaise. Les méthodes de action
peuvent parfaitement revenir aussi void
, au contraire à ce que certains IDEs vous croyez laisser via la validation EL. Notez que le PrimeFaces vitrine exemples sont jonchées de ce genre de actionListener
s sur tout lieu. Ceci est en effet mal. Ne pas utiliser cela comme une excuse pour faire que vous.
Dans les requêtes ajax, cependant, un gestionnaire d'exception spéciale est nécessaire. Ceci est peu importe si vous utilisez l'attribut listener
de <f:ajax>
ou non. Pour une explication et un exemple, la tête Gestion des exceptions dans JSF ajax demandes .
Autres conseils
Comme indiqué BalusC, le actionListener
par les exceptions par défaut, mais dans JSF 2.0, il est un peu plus à ce sujet. A savoir, il ne se contente pas des hirondelles et des journaux, mais en fait publie l'exception.
Cela se produit par un appel comme celui-ci:
context.getApplication().publishEvent(context, ExceptionQueuedEvent.class,
new ExceptionQueuedEventContext(context, exception, source, phaseId)
);
L'écouteur par défaut pour cet événement est le ExceptionHandler
qui, pour Mojarra est réglé sur com.sun.faces.context.ExceptionHandlerImpl
. Cette mise en œuvre essentiellement réémettre une exception, sauf lorsqu'elle concerne un AbortProcessingException, qui est connecté. ActionListeners enveloppent l'exception qui est levée par le code client dans un tel AbortProcessingException ce qui explique pourquoi ils sont toujours enregistrés.
Cette ExceptionHandler
peut être remplacé mais dans des faces-config.xml avec une implémentation personnalisée:
<exception-handlerfactory>
com.foo.myExceptionHandler
</exception-handlerfactory>
Au lieu d'écouter le monde, un seul haricot peut également écouter ces événements. Ce qui suit est une preuve de concept de ceci:
@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");
}
}
(note, ce n'est pas la façon dont on devrait normalement les auditeurs de code, cela est uniquement à des fins de démonstration!)
L'appel de cette d'un Facelet comme ceci:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:body>
<h:form>
<h:commandButton value="test" actionListener="#{myBean.actionMethod}"/>
</h:form>
</h:body>
</html>
entrainera dans une page d'erreur affiché.
ActionListener avait tiré le premier obtient, avec une option pour modifier la réponse, avant que l'action est appelée et détermine l'emplacement de la page suivante.
Si vous avez plusieurs boutons sur la même page qui devrait aller au même endroit, mais faire des choses légèrement différentes, vous pouvez utiliser la même action pour chaque bouton, mais utiliser un autre ActionListener pour gérer des fonctionnalités légèrement différentes.
Voici un lien qui décrit la relation:
http://www.java-samples.com/showtutorial.php? tutorialid = 605
TL; DR :
Les ActionListener
s (il peut y avoir plusieurs) exécuter dans l'ordre ont été enregistrés avant le action
Réponse longue :
Une entreprise action
invoque généralement un service EJB et si nécessaire définit également le résultat final et / ou accède à une vue différente
si ce n'est pas ce que vous faites un actionListener
est plus à-dire appropriée lorsque l'internaute interagit avec les composants, tels que h:commandButton
ou h:link
ils peuvent être manipulés en passant le nom de la méthode de bean géré en attribut actionListener
d'un composant d'interface utilisateur ou mettre en œuvre une interface ActionListener
et de transmettre le nom de classe d'implémentation d'attribut actionListener
d'un composant d'interface utilisateur.