Различия между действиями и действием
-
29-09-2019 - |
Вопрос
В чем разница между action
и actionListener
, и когда я должен использовать action
против actionListener
?
Решение
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
атрибут. Если бы они отсутствовали, Эль сразу же бросил бы javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean
, поскольку binding
Атрибут по умолчанию интерпретируется как выражение значения, а не как выражение метода. Добавление в стиле EL 2.2+ в скобках прозрачности превращает выражение значения в выражение метода. Смотрите также AO Почему я могу связатьu003Cf: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" />
Обратите внимание, что это, в свою очередь, указывает на плохой дизайн: навигация по почте. Это не пользователь, ни 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) {
// ...
}
В Мохарре, 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>
Для объяснения execute
и render
атрибуты, отправляйтесь в Понимание Primefaces Process / Update и JSF F: AJAX Execute / Render атрибуты.
Заказ о вызове
То actionListener
s всегда вызываются до то 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
, Напротив, что некоторые идентификаторы позволяют вам поверить через валидацию. Обратите внимание, что Primefaces витрина примеры усеяны такого рода actionListener
S над всем местом. Это действительно неправильно. Не используйте это как оправдание, чтобы сделать это самостоятельно.
Однако в запросах AJAX необходим специальный обработчик исключений. Это независимо от того, используете ли вы listener
атрибут <f:ajax>
или не. Для объяснения и примера, отправляйтесь в Обработка исключений в запросах JSF AJAX.
Другие советы
Как указал Балус, actionListener
По умолчанию ласточки исключения, но в JSF 2.0 есть немного больше для этого. А именно, это не просто глотает и логирует, но на самом деле публикует исключение.
Это происходит через такой звонок:
context.getApplication().publishEvent(context, ExceptionQueuedEvent.class,
new ExceptionQueuedEventContext(context, exception, source, phaseId)
);
Слушатель по умолчанию для этого события - это ExceptionHandler
что для Мохарры подразумевается com.sun.faces.context.ExceptionHandlerImpl
. Отказ Эта реализация в основном пересмотрит любое исключение, за исключением случаев, когда она касается AbortProcessingException, которое регистрируется. ActionListeners завершает исключение, которое бросается клиентским кодом в таком AbortProcessingException, которое объясняет, почему они всегда регистрируются.
Этот ExceptionHandler
Однако можно заменить в Faces-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");
}
}
(Обратите внимание, это не то, как обычно следует кодировать слушателей, это только для демонстрационных целей!)
Называя это с того, как это:
<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 сначала уволяется с возможностью изменения ответа, прежде чем действие вызывается и определяет расположение следующей страницы.
Если у вас есть несколько кнопок на одной и той же странице, которые должны перейти в одно и то же место, но делать немного разные вещи, вы можете использовать одно и то же действие для каждой кнопки, но использовать другой лист ActionListener, чтобы справиться с немного разными функциональными возможностями.
Вот ссылка, которая описывает отношения:
TL; доктор:
То ActionListener
S (может быть несколько) выполнить в том порядке, в котором они были зарегистрированы до action
Длинный ответ:
Бизнес action
Обычно вызывает сервис EJB, и, если необходимо, также устанавливает конечный результат и/или перемещается с другим представлением, если это не то, что вы делаете actionListener
более подходит, т.е. для тех, когда пользователь взаимодействует с компонентами, такими как h:commandButton
или h:link
Они могут быть обработаны, передавая имя метода управляемого компонента в actionListener
атрибут компонента интерфейса или для реализации ActionListener
интерфейс и передайте имя класса реализации actionListener
Атрибут компонента пользовательского интерфейса.