Различия между действием и actionListener
в чем разница между action
и actionListener
и когда я должен использовать action
и actionListener
?
3 ответов
actionListener
использовать actionListener
если вы хотите иметь крючок до реальное бизнес-действие выполняется, например, для его регистрации и / или установки дополнительного свойства (by <f:setPropertyActionListener>
), и/или иметь доступ к компоненту, который вызвал действие (которое доступно ActionEvent
. Если они отсутствовали, Эл смущенно бросал:--26-->, потому что binding
атрибут по умолчанию интерпретируется как выражение значения, а не как выражение метода. Добавление круглых скобок стиля EL 2.2+ прозрачно преобразует выражение значения в выражение метода. См. также.о'. почему я могу привязать
действие
использовать 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.
вызова ордер
на actionListener
s всегда вызываются до 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>
вызовет методы в следующем порядке:
Bean#ajaxListener()
Bean#actionListener()
ActionListenerType#processAction()
Bean#actionListenerBinding()
Bean#setProperty()
Bean#action()
обработка исключений
в actionListener
поддерживает специальное исключение: AbortProcessingException
. Если это исключение создается из actionListener
метод, затем JSF пропустит все оставшиеся прослушиватели действий и метод действий и приступит к отображению ответа напрямую. Вы не увидите страницу ошибки/исключения, однако JSF зарегистрирует ее. Это также неявно будет сделано, когда любое другое исключение создается из actionListener
. Таким образом, если вы намерены заблокировать страницу по странице ошибки в результате бизнес-исключения, то вы определенно должен выполнять работу в action
метод.
Если единственная причина, чтобы использовать actionListener
иметь void
метод, возвращающийся на ту же страницу, тогда это плохо. The action
методы могут отлично вернуться void
, в отличие от того, что некоторые IDEs позволяют вам верить через проверку EL. Обратите внимание, что витрина PrimeFaces примеры завалены такого рода actionListener
s повсюду. Это действительно неправильно. Не используйте это как извини, что тоже так делаешь.
однако в запросах 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 для обработки немного разных функций.
вот ссылка, которая описывает отношения: