Відмінності між дією та діями слухача


Відповіді:


583

actionListener

Використовуйте, actionListenerякщо ви хочете мати гачок перед виконанням справжньої ділової дії, наприклад, для реєстрації в ньому та / або для встановлення додаткової властивості (від <f:setPropertyActionListener>) та / або для доступу до компонента, який викликав дію (який доступнийActionEvent аргумент). Отже, виключно для підготовки цілей до того, як буде викликана реальна ділова дія.

actionListenerМетод має за замовчуванням такі підписи:

import javax.faces.event.ActionEvent;
// ...

public void actionListener(ActionEvent event) {
    // ...
}

І це має бути задекларовано так, без жодних методів в дужках:

<h:commandXxx ... actionListener="#{bean.actionListener}" />

Зауважте, що ви не можете передавати додаткові аргументи EL 2.2. Однак ви можете повністю змінити ActionEventаргумент, передавши та вказавши спеціальні аргументи. Наступні приклади є дійсними:

<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) {}

Зауважте важливість дужок у виразі методу без аргументів. Якщо вони відсутні, JSF все одно очікує методу зActionEvent аргументом.

Якщо ви користуєтеся версією EL 2.2+, ви можете оголосити методи прослуховування кількох дій через <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() {}

Зверніть увагу на важливість дужок в bindingатрибуті. Якщо вони відсутні, EL заплутано кине a javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean, оскільки bindingатрибут за замовчуванням інтерпретується як вираження значення, а не як вираз методу. Додавання круглих дужок стилю EL 2.2+ прозоро перетворює значення значення у вираження методу. Дивіться також ao Чому я можу прив’язати <f: actionListener> до довільного методу, якщо він не підтримується JSF?


дії

Використовуйте, actionякщо ви хочете виконати ділову дію, і, якщо потрібно, обробляйте навігацію. actionМетод може (таким чином, не повинен) повертати , Stringяка буде використовуватися в якості навігації випадку результату (цільової вид). Повернене значення nullабоvoid дозволить повернутись на ту саму сторінку і зберегти поточну область перегляду живою. Повернене значення порожнього рядка або того ж ідентифікатора перегляду також повернеться на ту саму сторінку, але відтворити область перегляду і таким чином знищити будь-які поточні активні квасолі перегляду та, якщо застосовно, відтворити їх.

actionМетод може бути будь-якими допустимими MethodExpression, також ті , які використовують EL 2.2 аргументів , наприклад , як показано нижче:

<h:commandXxx value="submit" action="#{bean.edit(item)}" />

За допомогою цього методу:

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

Зауважте, що, коли ваш метод дії виключно повертає рядок, ви також можете просто вказати саме цей рядок в actionатрибуті. Таким чином, це абсолютно незграбно:

<h:commandLink value="Go to next page" action="#{bean.goToNextpage}" />

За допомогою цього безглуздого методу повернення твердо кодованого рядка:

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

Замість цього просто покладіть цей жорстко закодований рядок безпосередньо в атрибут:

<h:commandLink value="Go to next page" action="nextpage" />

Зверніть увагу, що це в свою чергу вказує на поганий дизайн: навігація по POST. Це не є зручним для користувачів і не для SEO. Це все пояснено в Коли потрібно використовувати h: outputLink замість h: commandLink? і має вирішуватися як

<h:link value="Go to next page" outcome="nextpage" />

Див. Також Як орієнтуватися в JSF? Як зробити так, щоб URL відображав поточну сторінку (а не попередню) .


f: слухач ajax

Оскільки JSF 2.x є третім способом, то <f:ajax listener>.

<h:commandXxx ...>
    <f:ajax listener="#{bean.ajaxListener}" />
</h:commandXxx>

ajaxListenerМетод має за замовчуванням такі підписи:

import javax.faces.event.AjaxBehaviorEvent;
// ...

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

У Mojarra AjaxBehaviorEventаргумент необов’язковий, нижче працює як добре.

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

Але в MyFaces, це кине а MethodNotFoundException. Нижче працює в обох реалізаціях JSF, коли ви хочете опустити аргумент.

<h:commandXxx ...>
    <f:ajax execute="@form" listener="#{bean.ajaxListener()}" render="@form" />
</h:commandXxx>

Слухачі Ajax не дуже корисні для компонентів команди. Вони корисніші для введення та вибору компонентів <h:inputXxx>/ <h:selectXxx>. У компонентах команди просто дотримуйтесь actionта / або actionListenerдля наочності та кращого коду самодокументування. Більше того, як, наприклад actionListener, f:ajax listenerне підтримує повернення результатів навігації.

<h:commandXxx ... action="#{bean.action}">
    <f:ajax execute="@form" render="@form" />
</h:commandXxx>

Щоб отримати пояснення щодо атрибутів, перейдіть до розділу Розуміння процесу / оновлення PrimeFacesexecute та renderатрибутів JSF f: ajax Execute / render .


Порядок виклику

В actionListenerи завжди викликається передaction тим в тому ж порядку , як вони були оголошені в поданні і прикріплені до компоненту. Це f:ajax listenerзавжди викликається перед будь-яким слухачем дій. Отже, наступний приклад:

<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>

Викликатиме методи у такому порядку:

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

Обробка винятків

actionListenerПідтримує спеціальне виключення: AbortProcessingException. Якщо цей виняток буде викинуто з actionListenerметоду, тоді JSF пропустить будь-які інші слухачі дій та метод дії та перейде безпосередньо до відповіді. Сторінку помилки / винятку ви не побачите, проте JSF буде реєструвати її. Це також неявно буде зроблено, коли будь-який інший виняток буде викинуто з actionListener. Отже, якщо ви маєте намір заблокувати сторінку сторінкою помилок внаслідок винятку для бізнесу, то ви обов'язково повинні виконувати завдання в actionметоді.

Якщо єдина причина , щоб використовувати actionListenerце , щоб мати voidметод , який повертає до однієї і тієї ж сторінці, то це поганий. Ці actionметоди цілком можуть також повертати void, навпаки того , що деякі Іди нехай ви вважаєте , з допомогою перевірки EL. Зауважте, що приклади вітрин PrimeFaces всіяні подібними елементами actionListenerу всіх місцях. Це справді неправильно. Не використовуйте це як привід, щоб зробити це також самостійно.

Однак у запитах ajax потрібен спеціальний обробник винятків. Це незалежно від того, використовуєте ви listenerатрибут <f:ajax>чи ні. Для пояснення та прикладу, зверніться до обробки винятків у запитах ajax JSF .


1
Ви праві, що винятки в actionListeners проковтуються за замовчуванням, але в JSF 2.0 таку поведінку можна змінити. Детальну інформацію див. У моїй відповіді нижче.
Арджан Тіджмс

3
@arjan: ти маєш рацію, що JSF 2.0 дозволяє змінити обробку винятків за замовчуванням, які викинули actionListener, але це все ще не є гарним приводом для зловживань actionListenerдля ділових дій.
BalusC

1
Дійсно, ділові дії знаходяться в основному "потоці" циклу запитів / відповідей і лише цим actionвідповідають. actionListenerпризначений для вторинних матеріалів. Просто хотів уточнити, що винятки з actionListeners можна поширювати, якщо цього потрібно;)
Арджан Тіджмс

2
@Kawy: ім'я методу є вільним у виборі при використанні в actionListenerатрибуті, і воно повинно бути publicтаким же. processActionІм'я тільки обов'язковим , якщо ви використовуєте <f:actionListener type>, просто тому , що тип повинен реалізовувати ActionListenerінтерфейс , який має саме це ім'я методу processActionвизначається.
BalusC

2
@Muhammed: слухач дій Ajax викликається перед усіма слухачами звичайних дій. Зауважте, що навіть під час використання <f:ajax>, ви б у разі використання компонентів команди вважали за краще використовувати actionатрибут для ділових дій. Напр <h:commandButton action="#{bean.businessAction}"><f:ajax/></h:commandButton>.
BalusC

47

Як зазначав BalusC, actionListenerтипово поглинає винятки, але в JSF 2.0 є ще трохи. А саме, він не просто ластівки та колоди, а фактично публікує виняток.

Це відбувається через такий дзвінок:

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

ExceptionHandlerСлухачем за замовчуванням для цієї події є встановлений для Mojarra com.sun.faces.context.ExceptionHandlerImpl. Ця реалізація в основному повторно скине будь-який виняток, за винятком випадків, коли це стосується AbortProcessingException, який реєструється. ActionListeners переносять виняток, який викидається клієнтським кодом у такій AbortProcessingException, який пояснює, чому вони завжди реєструються.

Однак це ExceptionHandlerможе бути замінено у face-config.xml зі спеціальною реалізацією:

<exception-handlerfactory>
   com.foo.myExceptionHandler
</exception-handlerfactory>

Замість того, щоб слухати в усьому світі, один боб також може слухати ці події. Далі підтверджує концепцію цього:

@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");
    }

}

(зауважте, це не так, як зазвичай слід кодувати слухачів, це лише для демонстраційних цілей!)

Викликаючи це через Facelet так:

<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>

Це призведе до відображення сторінки помилок.


43

ActionListener спочатку звільняється з можливістю змінити відповідь до виклику Action та визначення місця розташування наступної сторінки.

Якщо у вас на одній сторінці є кілька кнопок, які мають переходити на одне і те ж місце, але робити дещо інші речі, ви можете використовувати одну й ту ж дію для кожної кнопки, але використовувати інший ActionListener для обробки трохи іншого функціоналу.

Ось посилання, яке описує відносини:

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


3
плюс один, Жирними літерами сказано майже все.
Ширгілл Фархан

0

TL; DR :

В ActionListeners (може бути кілька) виконуються в порядку їх реєстрації доaction

Довга відповідь :

Бізнес, actionяк правило, посилається на послугу EJB і, якщо необхідно, також встановлює кінцевий результат та / або переходить до іншого вигляду, якщо це не те, що ви робите, actionListenerє більш підходящим, тобто коли користувач взаємодіє з компонентами, такими як вони h:commandButtonабо h:linkвони можуть обробляти, передаючи ім'я керованого методу bean в actionListenerатрибут компонента інтерфейсу або впроваджуючи ActionListenerінтерфейс і передаючи ім'я класу реалізації actionListenerатрибуту компонента інтерфейсу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.