如果 JSF 不支持,为什么我可以将 <f:actionListener> 绑定到任意方法?

Why am I able to bind <f:actionListener> to an arbitrary method if it's not supported by JSF?

我正在使用 Glassfish 3.1.2.2 和 JSF Mojarra 2.1.6。

我有以下 Facelets 页面:

<h:form>
  <h:commandLink value="link">
    <f:actionListener binding="#{backingBean.someMethod(1)}"/>
  </h:commandLink>
</h:form>

以及以下辅助 bean:

@RequestScoped
@ManagedBean
public class BackingBean {
  public void someMethod(int i) {
    System.out.println("It was called: " + i);
  }
}

当我单击 link 时,"Info: It was called: 1" 出现在控制台中。

binding 的文档如下:

Library: http://xmlns.jcp.org/jsf/core, http://java.sun.com/jsf/core (Jsf Core)

Tag: actionListener

binding

Value binding expression that evaluates to an object that implements javax.faces.event.ActionListener. [emphasis mine]

此外,this question 的公认答案指出 f:actionListener 不可能调用任意方法。

如果不支持,为什么要调用支持 bean 方法?

这是新的 EL 2.2 功能的结果,它通过 #{bean.method()} 语法调用值表达式中的方法,而不是仅通过 #{bean.property} 语法引用 属性(这确实应该是确切的类型 ActionListener)。它不会在 EL 2.1 或更早的版本中工作,并且当您删除参数和括号时它也不会工作。该文档是在 EL 2.2 不存在时编写的(与 2006 年 5 月的 JSF 1.2 version 相比,它实际上没有修改;EL 2.2 于 2009 年 12 月推出)。然而,我同意它需要更新那部分,因为它会让初学者感到困惑。

您找到的答案基于文档提出了自己的观点,但是回答者似乎没有根据问题意识到虽然 binding="#{testController.nodeListener}" 失败了,但 binding="#{testController.nodeListener(event)}" 实际上 有效。这只是不给你通过 ActionEvent 的机会。如果它建议仅使用 binding="#{testController.nodeListener()}" 并以其他方式获取事件信息,例如通过调用 UIComponent#getCurrentComponent() 或什至将 #{component} 作为参数传递,则答案会更好。当然,只有当你真的需要用到它的时候。

<h:commandLink value="link">
    <f:actionListener binding="#{bean.someMethod(component)}"/>
</h:commandLink>
public void someMethod(UIComponent component) {
    System.out.println("It was called on: " + component); // HtmlCommandLink
}

另请参阅:

  • Invoke direct methods or methods with arguments / variables / parameters in EL
  • Difference between JSP EL, JSF EL and Unified EL
  • Differences between action and actionListener