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?

Author: BalusC, 2010-10-11

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ć do dowolnej metody, jeśli nie jest obsługiwana przez JSF?


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:

  1. Bean#ajaxListener()
  2. Bean#actionListener()
  3. ActionListenerType#processAction()
  4. Bean#actionListenerBinding()
  5. Bean#setProperty()
  6. 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.

 535
Author: BalusC,
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.

 44
Author: Arjan Tijms,
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:

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

 37
Author: Erick Robertson,
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