Różnice między akcją a actionListener
Jaka jest różnica między action
a actionListener
i kiedy należy użyć action
versus actionListener
?
3 answers
ActionListener
Użyj actionListener
Jeśli chcesz mieć hook zanim zostanie wykonana prawdziwa akcja biznesowa, np. aby ją zalogować i / lub ustawić dodatkową właściwość (przez <f:setPropertyActionListener>
), i / lub mieć dostęp do komponentu, który wywołał akcję (który jest dostępny przez ActionEvent
argument). Tak więc, wyłącznie w celu przygotowania, zanim zostanie wywołana prawdziwa akcja biznesowa.
Metoda actionListener
ma domyślnie następujący podpis:
import javax.faces.event.ActionEvent;
// ...
public void actionListener(ActionEvent event) {
// ...
}
I należy ją zadeklarować w następujący sposób, bez nawiasów metody:
<h:commandXxx ... actionListener="#{bean.actionListener}" />
Zauważ, że nie możesz przekazać dodatkowych argumentów przez EL 2.2. Można jednak całkowicie nadpisać argument ActionEvent
, przekazując i podając argumenty niestandardowe. Ważne są następujące przykłady:
<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) {}
Zwróć uwagę na znaczenie nawiasów w wyrażeniu metody argumentless. Gdyby ich nie było, JSF nadal oczekiwałby metody z argumentem ActionEvent
.
Jeśli jesteś na EL 2.2+, wtedy możesz zadeklarować wiele metod słuchacza akcji za pomocą <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() {}
Zwróć uwagę na znaczenie nawiasów w atrybucie binding
. Gdyby ich nie było, EL błędnie rzuciłby javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean
, ponieważ atrybut binding
jest domyślnie interpretowany jako wyrażenie wartości, a nie jako wyrażenie metody. Dodanie nawiasów stylów EL 2.2+ w przejrzysty sposób zamienia wyrażenie wartości w wyrażenie metody. Zobacz także a. o. Dlaczego jestem w stanie związać
Akcja
Użyj action
jeśli chcesz wykonać akcję biznesową i w razie potrzeby obsłuż nawigację. Metoda action
Może (a więc nie musi) zwracać String
, która będzie używana jako wynik przypadku nawigacyjnego (widok docelowy). Zwracana wartość null
lub void
pozwoli powrócić do tej samej strony i utrzymać bieżący zakres widoku. Zwracana wartość pustego łańcucha lub tego samego identyfikatora widoku będzie również powrócić do tej samej strony, ale odtworzyć zakres widoku, a tym samym zniszczyć wszystkie aktualnie aktywne fasole zakresu widoku i, jeśli dotyczy, odtworzyć je.
Metoda action
Może być dowolna MethodExpression
, również te, które używają argumentów EL 2.2, takich jak poniżej:
<h:commandXxx value="submit" action="#{bean.edit(item)}" />
Tą metodą:
public void edit(Item item) {
// ...
}
Zauważ, że gdy twoja metoda akcji zwraca wyłącznie łańcuch znaków, możesz również dokładnie określić ten łańcuch w atrybucie action
. Tak więc jest to całkowicie
<h:commandLink value="Go to next page" action="#{bean.goToNextpage}" />
Z tą bezsensowną metodą zwracającą zakodowany ciąg znaków:
public String goToNextpage() {
return "nextpage";
}
Zamiast tego, po prostu umieść ten zakodowany łańcuch bezpośrednio w atrybucie:
<h:commandLink value="Go to next page" action="nextpage" />
Proszę zauważyć, że to z kolei wskazuje na zły projekt: nawigowanie pocztą. To nie jest przyjazne dla użytkownika ani SEO. To wszystko jest wyjaśnione w Kiedy powinienem używać h: outputLink zamiast h:commandLink? i ma być rozwiązane jako
<h:link value="Go to next page" outcome="nextpage" />
Zobacz także jak poruszać się w JSF? Jak spraw, aby adres URL odzwierciedlał bieżącą stronę (a nie poprzednią) .
F: Ajax listener
Od JSF 2.x jest trzecia droga, <f:ajax listener>
.
<h:commandXxx ...>
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandXxx>
Metoda ajaxListener
ma domyślnie następujący podpis:
import javax.faces.event.AjaxBehaviorEvent;
// ...
public void ajaxListener(AjaxBehaviorEvent event) {
// ...
}
W Mojarrze argument AjaxBehaviorEvent
jest opcjonalny, poniżej działa jako dobry.
public void ajaxListener() {
// ...
}
/ Align = "left" / Poniżej działa w obu implementacjach JSF, gdy chcesz pominąć argument.
<h:commandXxx ...>
<f:ajax execute="@form" listener="#{bean.ajaxListener()}" render="@form" />
</h:commandXxx>
Ajax nie są tak naprawdę przydatne w komponentach poleceń. Są bardziej przydatne przy wprowadzaniu i wyborze komponentów <h:inputXxx>
/<h:selectXxx>
. W komponentach polecenia, po prostu trzymaj się action
i/lub actionListener
dla jasności i lepszego samodokumentowania kodu. Ponadto, podobnie jak actionListener
, f:ajax listener
nie obsługuje zwracania wyniku nawigacji.
<h:commandXxx ... action="#{bean.action}">
<f:ajax execute="@form" render="@form" />
</h:commandXxx>
Aby uzyskać wyjaśnienie atrybutów execute
i render
, przejdź do Understanding primefaces process/update i JSF f: ajax execute/render atrybuty .
Rozkaz wywołania
actionListener
S są zawsze wywoływane przed action
w tej samej kolejności, w jakiej zostały zadeklarowane w widoku i dołączone do komponentu. {[45] } jest zawsze wywoływany przed {[85] } jakąkolwiek akcją. Tak więc, następujący przykład:
<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>
Wywoła metody w następujący sposób zamówienie:
Bean#ajaxListener()
Bean#actionListener()
ActionListenerType#processAction()
Bean#actionListenerBinding()
Bean#setProperty()
Bean#action()
Obsługa wyjątków
actionListener
obsługuje specjalny wyjątek: AbortProcessingException
. Jeśli ten wyjątek zostanie wyrzucony z metody actionListener
, to JSF pominie Pozostałe detektory akcji i metodę akcji i rozpocznie renderowanie odpowiedzi bezpośrednio. Nie zobaczysz strony błędu/wyjątku, jednak JSF ją zarejestruje. To będzie również domyślnie wykonywane, gdy jakikolwiek inny wyjątek jest wyrzucany z actionListener
. Tak więc, jeśli zamierzasz zablokować stronę przez stronę błędu w wyniku wyjątku biznesowego, zdecydowanie powinieneś wykonywać zadanie w metodzie action
.
Jeśli jedynym powodem użycia metody actionListener
jest powrót metody void
do tej samej strony, to jest to złe. Metody action
mogą również doskonale zwracać void
, W przeciwieństwie do tego, w co niektóre IDE pozwalają ci wierzyć poprzez walidację EL. Zauważ, że przykłady primefaces showcase są zaśmiecone takimi przykładami actionListener
wszędzie. To jest rzeczywiście złe. Nie używaj tego jako wymówki, żeby zrobić to sam.
W żądaniach ajax potrzebna jest jednak Specjalna obsługa wyjątków. Jest to niezależnie od tego, czy używasz listener
atrybutu <f:ajax>
, czy nie. Aby uzyskać wyjaśnienie i przykład, przejdź do obsługi wyjątków w żądaniach JSF ajax.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:26
Jak zauważył BalusC, actionListener
domyślnie połyka wyjątki, ale w JSF 2.0 jest tego trochę więcej. Mianowicie, nie tylko połyka i rejestruje, ale w rzeczywistości publikuje wyjątek.
Dzieje się to poprzez wywołanie takie jak:
context.getApplication().publishEvent(context, ExceptionQueuedEvent.class,
new ExceptionQueuedEventContext(context, exception, source, phaseId)
);
Domyślnym detektorem tego zdarzenia jest ExceptionHandler
, który dla Mojarry jest ustawiony na com.sun.faces.context.ExceptionHandlerImpl
. Implementacja ta zasadniczo zmieni wszelkie wyjątki, z wyjątkiem sytuacji, gdy dotyczy to AbortProcessingException, która jest rejestrowana. ActionListeners zawija wyjątek, który jest wyrzucany przez kod klienta w taki AbortProcessingException, co wyjaśnia, dlaczego są one zawsze rejestrowane.
To ExceptionHandler
można jednak zastąpić w faces-config.xml z niestandardową implementacją:
<exception-handlerfactory>
com.foo.myExceptionHandler
</exception-handlerfactory>
Zamiast słuchać globalnie, jedna fasola może również słuchać tych wydarzeń. Poniżej znajduje się dowód koncepcji tego:
@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");
}
}
(uwaga, nie tak powinno się normalnie kodować słuchaczy, jest to tylko dla cele demonstracyjne!)
Wywołanie tego z twarzy takiej jak ta:
<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>
Spowoduje wyświetlenie strony błędu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-19 14:40:50
ActionListener jest uruchamiany jako pierwszy, z opcją modyfikacji odpowiedzi, zanim akcja zostanie wywołana i określi lokalizację następnej strony.
Jeśli masz kilka przycisków na tej samej stronie, które powinny iść do tego samego miejsca, ale robią nieco inne rzeczy, możesz użyć tej samej akcji dla każdego przycisku, ale użyj innego ActionListener, aby obsłużyć nieco inną funkcjonalność.
Oto link opisujący relacja:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-11 19:38:54