У чому різниця між actionі actionListenerі коли я повинен використовувати actionпроти actionListener?
У чому різниця між actionі actionListenerі коли я повинен використовувати actionпроти 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 відображав поточну сторінку (а не попередню) .
Оскільки 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>
Викликатиме методи у такому порядку:
Bean#ajaxListener()Bean#actionListener()ActionListenerType#processAction()Bean#actionListenerBinding()Bean#setProperty()Bean#action()actionListenerПідтримує спеціальне виключення: AbortProcessingException. Якщо цей виняток буде викинуто з actionListenerметоду, тоді JSF пропустить будь-які інші слухачі дій та метод дії та перейде безпосередньо до відповіді. Сторінку помилки / винятку ви не побачите, проте JSF буде реєструвати її. Це також неявно буде зроблено, коли будь-який інший виняток буде викинуто з actionListener. Отже, якщо ви маєте намір заблокувати сторінку сторінкою помилок внаслідок винятку для бізнесу, то ви обов'язково повинні виконувати завдання в actionметоді.
Якщо єдина причина , щоб використовувати actionListenerце , щоб мати voidметод , який повертає до однієї і тієї ж сторінці, то це поганий. Ці actionметоди цілком можуть також повертати void, навпаки того , що деякі Іди нехай ви вважаєте , з допомогою перевірки EL. Зауважте, що приклади вітрин PrimeFaces всіяні подібними елементами actionListenerу всіх місцях. Це справді неправильно. Не використовуйте це як привід, щоб зробити це також самостійно.
Однак у запитах ajax потрібен спеціальний обробник винятків. Це незалежно від того, використовуєте ви listenerатрибут <f:ajax>чи ні. Для пояснення та прикладу, зверніться до обробки винятків у запитах ajax JSF .
actionListener, але це все ще не є гарним приводом для зловживань actionListenerдля ділових дій.
actionвідповідають. actionListenerпризначений для вторинних матеріалів. Просто хотів уточнити, що винятки з actionListeners можна поширювати, якщо цього потрібно;)
actionListenerатрибуті, і воно повинно бути publicтаким же. processActionІм'я тільки обов'язковим , якщо ви використовуєте <f:actionListener type>, просто тому , що тип повинен реалізовувати ActionListenerінтерфейс , який має саме це ім'я методу processActionвизначається.
<f:ajax>, ви б у разі використання компонентів команди вважали за краще використовувати actionатрибут для ділових дій. Напр <h:commandButton action="#{bean.businessAction}"><f:ajax/></h:commandButton>.
Як зазначав 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>
Це призведе до відображення сторінки помилок.
ActionListener спочатку звільняється з можливістю змінити відповідь до виклику Action та визначення місця розташування наступної сторінки.
Якщо у вас на одній сторінці є кілька кнопок, які мають переходити на одне і те ж місце, але робити дещо інші речі, ви можете використовувати одну й ту ж дію для кожної кнопки, але використовувати інший ActionListener для обробки трохи іншого функціоналу.
Ось посилання, яке описує відносини:
TL; DR :
В ActionListeners (може бути кілька) виконуються в порядку їх реєстрації доaction
Довга відповідь :
Бізнес, actionяк правило, посилається на послугу EJB і, якщо необхідно, також встановлює кінцевий результат та / або переходить до іншого вигляду, якщо це не те, що ви робите, actionListenerє більш підходящим, тобто коли користувач взаємодіє з компонентами, такими як вони h:commandButtonабо h:linkвони можуть обробляти, передаючи ім'я керованого методу bean в actionListenerатрибут компонента інтерфейсу або впроваджуючи ActionListenerінтерфейс і передаючи ім'я класу реалізації actionListenerатрибуту компонента інтерфейсу.