动作监听器
Use actionListener
如果你想要一个钩子before真正的业务行动得到执行,例如记录它,和/或设置附加属性(通过<f:setPropertyActionListener> https://docs.oracle.com/javaee/7/javaserver-faces-2-2/vdldocs-facelets/f/setPropertyActionListener.html),和/或访问调用该操作的组件(可通过ActionEvent http://docs.oracle.com/javaee/7/api/javax/faces/event/ActionEvent.html争论)。因此,纯粹是为了在调用实际业务操作之前进行准备。
The 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 会令人困惑地抛出一个javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean
,因为binding
默认情况下,属性被解释为值表达式,而不是方法表达式。添加 EL 2.2+ 风格的括号可以将值表达式透明地转换为方法表达式。另请参见 a.o.如果 JSF 不支持,为什么我能够将 绑定到任意方法? https://stackoverflow.com/questions/30744949/why-am-i-able-to-bind-factionlistener-to-an-arbitrary-method-if-its-not-supp
action
Use action
如果您想执行业务操作并在必要时处理导航。这action
方法可以(因此,不是必须)返回一个String
它将用作导航案例结果(目标视图)。返回值为null
or void
将让它返回到同一页面并保持当前视图范围处于活动状态。空字符串或相同视图 ID 的返回值也将返回到同一页面,但会重新创建视图范围,从而销毁任何当前活动的视图范围 bean,并在适用时重新创建它们。
The action
方法可以是任何有效的MethodExpression http://docs.oracle.com/javaee/7/api/javax/el/MethodExpression.html,还有使用 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? https://stackoverflow.com/questions/4317684/when-should-i-use-houtputlink-instead-of-hcommandlink/4317723#4317723并且应该被解决为
<h:link value="Go to next page" outcome="nextpage" />
也可以看看如何在 JSF 中导航?如何使 URL 反映当前页面(而不是上一页) https://stackoverflow.com/questions/15521451/how-to-navigate-in-jsf-how-to-make-url-reflect-current-page-and-not-previous-o.
f:ajax 监听器
从 JSF 2.x 开始,出现了第三种方法,即<f:ajax listener>
.
<h:commandXxx ...>
<f:ajax listener="#{bean.ajaxListener}" />
</h:commandXxx>
The 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
and/or actionListener
为了清晰和更好的自记录代码。而且,像actionListener
, the f:ajax listener
不支持返回导航结果。
<h:commandXxx ... action="#{bean.action}">
<f:ajax execute="@form" render="@form" />
</h:commandXxx>
对于解释execute
and render
属性,前往了解 PrimeFaces 进程/更新和 JSF f:ajax 执行/渲染属性 https://stackoverflow.com/questions/25339056/understanding-primefaces-process-update-and-jsf-fajax-execute-render-attributes.
调用顺序
The actionListener
s 总是被调用before the action
其顺序与在视图中声明并附加到组件的顺序相同。这f:ajax listener
总是被调用before任何动作监听器。所以,下面的例子:
<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()
异常处理
The actionListener
支持特殊异常:AbortProcessingException http://docs.oracle.com/javaee/7/api/javax/faces/event/AbortProcessingException.html。如果此异常是从actionListener
方法,那么 JSF 将跳过任何剩余的操作侦听器和操作方法,并直接继续渲染响应。您不会看到错误/异常页面,但 JSF 会记录它。每当从某个对象抛出任何其他异常时,这也会隐式完成。actionListener
。因此,如果您打算因业务异常而通过错误页面来阻止该页面,那么您绝对应该在action
method.
如果使用的唯一原因是actionListener
就是有一个void
方法返回同一页面,那么这是一个坏方法。这action
方法也可以完美返回void
,与某些 IDE 通过 EL 验证让您相信的相反。请注意,PrimeFaces 展示 http://www.primefaces.org/showcase/这种例子比比皆是actionListener
遍布所有地方。这确实是错误的。不要以此为借口自己也这样做。
然而,在 ajax 请求中,需要一个特殊的异常处理程序。这与您是否使用listener
的属性<f:ajax>
或不。如需解释和示例,请前往JSF ajax 请求中的异常处理 https://stackoverflow.com/questions/27526753/exception-handling-in-jsf-ajax-requests.