У чому різниця між 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
призначений для вторинних матеріалів. Просто хотів уточнити, що винятки з actionListener
s можна поширювати, якщо цього потрібно;)
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 :
В ActionListener
s (може бути кілька) виконуються в порядку їх реєстрації доaction
Довга відповідь :
Бізнес, action
як правило, посилається на послугу EJB і, якщо необхідно, також встановлює кінцевий результат та / або переходить до іншого вигляду, якщо це не те, що ви робите, actionListener
є більш підходящим, тобто коли користувач взаємодіє з компонентами, такими як вони h:commandButton
або h:link
вони можуть обробляти, передаючи ім'я керованого методу bean в actionListener
атрибут компонента інтерфейсу або впроваджуючи ActionListener
інтерфейс і передаючи ім'я класу реалізації actionListener
атрибуту компонента інтерфейсу.