ActionListener
Verwenden Sie actionListener
wenn Sie einen Haken haben wollen antes de die eigentliche Geschäftsaktion ausgeführt wird, z.B. um sie zu protokollieren, und/oder um eine zusätzliche Eigenschaft zu setzen (durch <f:setPropertyActionListener>
), und/oder um Zugang zu der Komponente zu haben, die die Aktion aufgerufen hat (verfügbar über ActionEvent
Argument). Es dient also lediglich der Vorbereitung, bevor die eigentliche Geschäftsaktion aufgerufen wird.
En actionListener
Methode hat standardmäßig die folgende Signatur:
import javax.faces.event.ActionEvent;
// ...
public void actionListener(ActionEvent event) {
// ...
}
Und es soll wie folgt deklariert werden, ohne Klammern:
<h:commandXxx ... actionListener="#{bean.actionListener}" />
Beachten Sie, dass Sie nicht zusätzlich Argumente von EL 2.2. Sie können jedoch die ActionEvent
Argument insgesamt durch Übergabe und Angabe von benutzerdefinierten Argumenten. Die folgenden Beispiele sind gültig:
<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) {}
Beachten Sie die Bedeutung der Klammern in dem argumentlosen Methodenausdruck. Würden sie fehlen, würde JSF immer noch eine Methode mit ActionEvent
Argument.
Wenn Sie EL 2.2+ verwenden, können Sie mehrere Action-Listener-Methoden über <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() {}
Beachten Sie die Bedeutung der Klammern in der binding
zuordnen. Wenn sie fehlten, würde EL verwirrenderweise ein javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean
denn die binding
Attribut wird standardmäßig als Wertausdruck und nicht als Methodenausdruck interpretiert. Das Hinzufügen von Klammern im Stil von EL 2.2+ verwandelt einen Wertausdruck transparent in einen Methodenausdruck. Siehe auch a.o. Warum kann ich <f:actionListener> an eine beliebige Methode binden, wenn sie von JSF nicht unterstützt wird?
Aktion
Verwenden Sie action
wenn Sie eine geschäftliche Aktion ausführen und gegebenenfalls die Navigation steuern wollen. Die action
Methode kann (muss also nicht) eine String
die als Navigationsfallergebnis (die Zielansicht) verwendet wird. Ein Rückgabewert von null
o void
lässt ihn zur gleichen Seite zurückkehren und hält den aktuellen Ansichtsbereich am Leben. Ein Rückgabewert von einer leeren Zeichenkette oder der gleichen View-ID führt ebenfalls zur gleichen Seite zurück, erstellt aber den View-Bereich neu und zerstört somit alle derzeit aktiven View-Scoped Beans und erstellt sie gegebenenfalls neu.
En action
kann jede gültige Methode sein MethodExpression
auch diejenigen, die EL 2.2 Argumente wie die folgenden verwenden:
<h:commandXxx value="submit" action="#{bean.edit(item)}" />
Mit dieser Methode:
public void edit(Item item) {
// ...
}
Beachten Sie, dass Sie, wenn Ihre Aktionsmethode lediglich eine Zeichenkette zurückgibt, auch genau diese Zeichenkette in der action
Attribut. Dies ist also völlig ungeschickt:
<h:commandLink value="Go to next page" action="#{bean.goToNextpage}" />
Mit dieser sinnlosen Methode, die eine hartkodierte Zeichenfolge zurückgibt:
public String goToNextpage() {
return "nextpage";
}
Geben Sie stattdessen einfach die hartkodierte Zeichenfolge direkt in das Attribut ein:
<h:commandLink value="Go to next page" action="nextpage" />
Bitte beachten Sie, dass dies wiederum auf ein schlechtes Design hinweist: die Navigation per POST. Dies ist weder benutzer- noch SEO-freundlich. Dies alles wird erklärt in Wann sollte ich h:outputLink anstelle von h:commandLink verwenden? und soll gelöst werden als
<h:link value="Go to next page" outcome="nextpage" />
Siehe auch Wie navigiert man in JSF? Wie kann die URL die aktuelle Seite (und nicht die vorherige) anzeigen? .
f:ajax Zuhörer
Seit JSF 2.x gibt es einen dritten Weg, die <f:ajax listener>
.
<h:commandXxx ...>
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandXxx>
En ajaxListener
Methode hat standardmäßig die folgende Signatur:
import javax.faces.event.AjaxBehaviorEvent;
// ...
public void ajaxListener(AjaxBehaviorEvent event) {
// ...
}
In Mojarra, dem AjaxBehaviorEvent
Argument ist optional, unten funktioniert es genauso gut.
public void ajaxListener() {
// ...
}
Aber in MyFaces, würde es eine MethodNotFoundException
. Unten funktioniert in beiden JSF-Implementierungen, wenn Sie das Argument weglassen wollen.
<h:commandXxx ...>
<f:ajax execute="@form" listener="#{bean.ajaxListener()}" render="@form" />
</h:commandXxx>
Ajax-Listener sind bei Befehlskomponenten nicht wirklich nützlich. Sie sind nützlicher für Eingabe- und Auswahlkomponenten <h:inputXxx>
/ <h:selectXxx>
. In Befehlskomponenten bleiben Sie einfach bei action
und/oder actionListener
für mehr Klarheit und eine bessere Selbstdokumentation des Codes. Außerdem, wie actionListener
die f:ajax listener
unterstützt nicht die Rückgabe eines Navigationsergebnisses.
<h:commandXxx ... action="#{bean.action}">
<f:ajax execute="@form" render="@form" />
</h:commandXxx>
Zur Erklärung von execute
y render
Attribute, gehen Sie zu Verständnis von PrimeFaces process/update und JSF f:ajax execute/render attributes .
Aufforderungsanordnung
En actionListener
s werden immer aufgerufen antes de die action
in der gleichen Reihenfolge, in der sie in der Ansicht deklariert und an die Komponente angehängt wurden. Die f:ajax listener
wird immer aufgerufen antes de jede Aktion Hörer. Also, das folgende Beispiel:
<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>
Ruft die Methoden in der folgenden Reihenfolge auf:
Bean#ajaxListener()
Bean#actionListener()
ActionListenerType#processAction()
Bean#actionListenerBinding()
Bean#setProperty()
Bean#action()
Behandlung von Ausnahmen
En actionListener
unterstützt eine besondere Ausnahme: AbortProcessingException
. Wenn diese Ausnahme von einer actionListener
Methode, dann überspringt JSF alle verbleibenden Action-Listener und die Action-Methode und fährt direkt mit dem Rendern der Antwort fort. Es wird keine Fehler-/Ausnahmeseite angezeigt, JSF protokolliert sie jedoch. Dies geschieht auch implizit immer dann, wenn eine andere Ausnahme von einer anderen Methode geworfen wird. actionListener
. Wenn Sie also beabsichtigen, die Seite durch eine Fehlerseite als Ergebnis einer Geschäftsausnahme zu blockieren, dann sollten Sie auf jeden Fall die Arbeit in der action
Methode.
Wenn der einzige Grund für die Verwendung eines actionListener
ist es, eine void
Methode, die zur gleichen Seite zurückkehrt, dann ist das schlecht. Die action
Methoden können perfekt auch zurückgeben void
im Gegensatz zu dem, was einige IDEs über die EL-Validierung glauben machen. Beachten Sie, dass die PrimeFaces Schaufenster Die Beispiele sind voll von dieser Art von actionListener
s über den ganzen Platz. Das ist in der Tat falsch. Benutzen Sie das nicht als Ausrede, um das auch selbst zu tun.
Bei Ajax-Anfragen ist jedoch ein spezieller Exception-Handler erforderlich. Dies ist unabhängig davon, ob Sie listener
Attribut von <f:ajax>
oder nicht. Eine Erklärung und ein Beispiel finden Sie unter Ausnahmebehandlung in JSF-Ajax-Anfragen .