Вопрос

В чем разница между 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 атрибуты.


Заказ о вызове

То actionListeners всегда вызываются до то 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, Напротив, что некоторые идентификаторы позволяют вам поверить через валидацию. Обратите внимание, что Primefaces витрина примеры усеяны такого рода actionListenerS над всем местом. Это действительно неправильно. Не используйте это как оправдание, чтобы сделать это самостоятельно.

Однако в запросах 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, чтобы справиться с немного разными функциональными возможностями.

Вот ссылка, которая описывает отношения:

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

TL; доктор:

То ActionListenerS (может быть несколько) выполнить в том порядке, в котором они были зарегистрированы до action

Длинный ответ:

Бизнес action Обычно вызывает сервис EJB, и, если необходимо, также устанавливает конечный результат и/или перемещается с другим представлением, если это не то, что вы делаете actionListener более подходит, т.е. для тех, когда пользователь взаимодействует с компонентами, такими как h:commandButton или h:link Они могут быть обработаны, передавая имя метода управляемого компонента в actionListener атрибут компонента интерфейса или для реализации ActionListener интерфейс и передайте имя класса реализации actionListener Атрибут компонента пользовательского интерфейса.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top