Различия между действием и actionListener

в чем разница между action и actionListener и когда я должен использовать action и actionListener?

3 ответов


actionListener

использовать actionListener если вы хотите иметь крючок до реальное бизнес-действие выполняется, например, для его регистрации и / или установки дополнительного свойства (by <f:setPropertyActionListener>), и/или иметь доступ к компоненту, который вызвал действие (которое доступно ActionEvent. Если они отсутствовали, Эл смущенно бросал:--26-->, потому что binding атрибут по умолчанию интерпретируется как выражение значения, а не как выражение метода. Добавление круглых скобок стиля EL 2.2+ прозрачно преобразует выражение значения в выражение метода. См. также.о'. почему я могу привязать к произвольному методу, если он не поддерживается JSF?


действие

использовать action если вы хотите выполнить бизнес действий и при необходимости отрегулировать навигации. The action метод может (таким образом, не должен) вернуть a String который будет использоваться в качестве результата навигационного случая (целевой вид). Возвращаемое значение null или void позволит ему вернуться на ту же страницу и сохранить текущую область просмотра. Возвращаемое значение пустой строки или того же ID представления также возвращается на ту же страницу, но воссоздает область представления и, таким образом, уничтожает все активные бобы области представления и, если применимо, воссоздает их.

на action метод может быть любым допустимым MethodExpression, также те, которые используют аргументы EL 2.2, такие как ниже:

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

с этим метод:

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

обратите внимание, что когда ваш метод действия возвращает только строку, вы также можете просто указать именно эту строку в . Таким образом, это совершенно неуклюже:

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

начиная с 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, the f:ajax listener не поддерживает возврат результата навигации.

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

для объяснения на execute и render атрибуты, головой к понимание процесса/обновления PrimeFaces и JSF f:ajax execute/render attributes.


вызова ордер

на actionListeners всегда вызываются до the action в том же порядке, в котором они были объявлены в представлении и прикреплен к компоненту. The 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 метод, возвращающийся на ту же страницу, тогда это плохо. The action методы могут отлично вернуться void, в отличие от того, что некоторые IDEs позволяют вам верить через проверку EL. Обратите внимание, что витрина PrimeFaces примеры завалены такого рода actionListeners повсюду. Это действительно неправильно. Не используйте это как извини, что тоже так делаешь.

однако в запросах ajax требуется специальный обработчик исключений. Это независимо от того, используете ли вы на <f:ajax> или нет. Для объяснения и примера, head to обработка исключений в запросах ajax JSF.


как 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 может быть заменен, однако, в 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