action 和 actionListener 的区别 [英] Differences between action and actionListener

查看:20
本文介绍了action 和 actionListener 的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

actionactionListener 之间有什么区别,我应该什么时候使用 actionactionListener?

What is the difference between action and actionListener, and when should I use action versus actionListener?

推荐答案

actionListener

使用 actionListener 如果您希望在实际业务操作执行之前有一个钩子,例如记录它,和/或设置附加属性(通过 <f:setPropertyActionListener>),和/或访问调用操作的组件(可通过 ActionEvent 参数).因此,纯粹是为了在调用实际业务操作之前做好准备.

actionListener

Use actionListener if you want have a hook before the real business action get executed, e.g. to log it, and/or to set an additional property (by <f:setPropertyActionListener>), and/or to have access to the component which invoked the action (which is available by ActionEvent argument). So, purely for preparing purposes before the real business action gets invoked.

actionListener 方法默认具有以下签名:

The actionListener method has by default the following signature:

import javax.faces.event.ActionEvent;
// ...

public void actionListener(ActionEvent event) {
    // ...
}

它应该声明如下,没有任何方法括号:

And it's supposed to be declared as follows, without any method parentheses:

<h:commandXxx ... actionListener="#{bean.actionListener}" />

请注意,EL 2.2 不能传递附加 参数.但是,您可以通过传递和指定自定义参数来完全覆盖 ActionEvent 参数.以下示例有效:

Note that you can't pass additional arguments by EL 2.2. You can however override the ActionEvent argument altogether by passing and specifying custom argument(s). The following examples are valid:

<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 参数的方法.

Note the importance of the parentheses in the argumentless method expression. If they were absent, JSF would still expect a method with ActionEvent argument.

如果您使用的是 EL 2.2+,那么您可以通过 声明多个动作侦听器方法.

If you're on EL 2.2+, then you can declare multiple action listener methods via <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 属性是由default 解释为值表达式,而不是方法表达式.添加 EL 2.2+ 样式的括号可以透明地将值表达式转换为方法表达式.另见 a.o.为什么是我能够绑定 <f:actionListener>如果 JSF 不支持任意方法?

Note the importance of the parentheses in the binding attribute. If they were absent, EL would confusingly throw a javax.el.PropertyNotFoundException: Property 'actionListener1' not found on type com.example.Bean, because the binding attribute is by default interpreted as a value expression, not as a method expression. Adding EL 2.2+ style parentheses transparently turns a value expression into a method expression. See also a.o. Why am I able to bind <f:actionListener> to an arbitrary method if it's not supported by JSF?

如果您想执行业务操作并在必要时处理导航,请使用 action.action 方法可以(因此,不是必须)返回一个 String ,它将用作导航案例结果(目标视图).nullvoid 的返回值将让它返回到同一页面并保持当前视图范围活跃.空字符串或相同视图 ID 的返回值也将返回到同一页面,但会重新创建视图范围,从而销毁所有当前处于活动状态的视图范围 bean,如果适用,则重新创建它们.

Use action if you want to execute a business action and if necessary handle navigation. The action method can (thus, not must) return a String which will be used as navigation case outcome (the target view). A return value of null or void will let it return to the same page and keep the current view scope alive. A return value of an empty string or the same view ID will also return to the same page, but recreate the view scope and thus destroy any currently active view scoped beans and, if applicable, recreate them.

action 方法可以是任何有效的 MethodExpression,还有使用 EL 2.2 参数的那些,例如:

The action method can be any valid MethodExpression, also the ones which uses EL 2.2 arguments such as below:

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

使用这种方法:

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

请注意,当您的操作方法仅返回一个字符串时,您也可以在 action 属性中准确指定该字符串.因此,这完全是笨拙的:

Note that when your action method solely returns a string, then you can also just specify exactly that string in the action attribute. Thus, this is totally clumsy:

<h:commandLink value="Go to next page" action="#{bean.goToNextpage}" />

使用这种无意义的方法返回一个硬编码的字符串:

With this senseless method returning a hardcoded string:

public String goToNextpage() {
    return "nextpage";
}

相反,只需将硬编码字符串直接放在属性中:

Instead, just put that hardcoded string directly in the attribute:

<h:commandLink value="Go to next page" action="nextpage" />

请注意,这反过来表明设计不佳:通过 POST 导航.这对用户和 SEO 都不友好.这一切都在 我应该何时使用 h:outputLink 中进行了解释而不是 h:commandLink? 并且应该被解决为

Please note that this in turn indicates a bad design: navigating by POST. This is not user nor SEO friendly. This all is explained in When should I use h:outputLink instead of h:commandLink? and is supposed to be solved as

<h:link value="Go to next page" outcome="nextpage" />

另见 如何在 JSF 中导航?如何使 URL 反映当前页面(而不是前一个页面).

从 JSF 2.x 开始,还有第三种方式,.

Since JSF 2.x there's a third way, the <f:ajax listener>.

<h:commandXxx ...>
    <f:ajax listener="#{bean.ajaxListener}" />
</h:commandXxx>

ajaxListener 方法默认具有以下签名:

The ajaxListener method has by default the following signature:

import javax.faces.event.AjaxBehaviorEvent;
// ...

public void ajaxListener(AjaxBehaviorEvent event) {
    // ...
}

在 Mojarra 中,AjaxBehaviorEvent 参数是可选的,下面同样有效.

In Mojarra, the AjaxBehaviorEvent argument is optional, below works as good.

public void ajaxListener() {
    // ...
}

但在 MyFaces 中,它会抛出一个 MethodNotFoundException.当您想省略参数时,以下两种 JSF 实现都适用.

But in MyFaces, it would throw a MethodNotFoundException. Below works in both JSF implementations when you want to omit the argument.

<h:commandXxx ...>
    <f:ajax execute="@form" listener="#{bean.ajaxListener()}" render="@form" />
</h:commandXxx>

Ajax 侦听器在命令组件上并不是很有用.它们在输入和选择组件 / 上更有用.在命令组件中,为了清晰和更好的自文档化代码,只需坚持使用 action 和/或 actionListener.此外,与 actionListener 一样,f:ajax listener 不支持返回导航结果.

Ajax listeners are not really useful on command components. They are more useful on input and select components <h:inputXxx>/<h:selectXxx>. In command components, just stick to action and/or actionListener for clarity and better self-documenting code. Moreover, like actionListener, the f:ajax listener does not support returning a navigation outcome.

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

有关 executerender 属性的说明,请前往 了解 PrimeFaces 进程/更新和 JSF f:ajax 执行/渲染属性.

For explanation on execute and render attributes, head to Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes.

actionListener 总是在 action 之前以与它们在视图中声明并附加到组件相同的顺序被调用.f:ajax 侦听器 总是在 任何动作侦听器之前被调用.所以,下面的例子:

The actionListeners are always invoked before the action in the same order as they are been declared in the view and attached to the component. The f:ajax listener is always invoked before any action listener. So, the following example:

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

将按以下顺序调用方法:

Will invoke the methods in the following order:

  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 方法中执行该作业.


Exception handling

The actionListener supports a special exception: AbortProcessingException. If this exception is thrown from an actionListener method, then JSF will skip any remaining action listeners and the action method and proceed to render response directly. You won't see an error/exception page, JSF will however log it. This will also implicitly be done whenever any other exception is being thrown from an actionListener. So, if you intend to block the page by an error page as result of a business exception, then you should definitely be performing the job in the action method.

如果使用 actionListener 的唯一原因是让 void 方法返回同一页面,那么这是一个糟糕的方法.action 方法也可以完美地返回 void,这与某些 IDE 通过 EL 验证让您相信的相反.请注意,PrimeFaces 展示 示例中到处都是这种actionListener所有的地方.这确实是错误的.不要以此为借口,自己也这样做.

If the sole reason to use an actionListener is to have a void method returning to the same page, then that's a bad one. The action methods can perfectly also return void, on the contrary to what some IDEs let you believe via EL validation. Note that the PrimeFaces showcase examples are littered with this kind of actionListeners over all place. This is indeed wrong. Don't use this as an excuse to also do that yourself.

然而,在 ajax 请求中,需要一个特殊的异常处理程序.这与您是否使用 listener 属性无关.如需解释和示例,请前往JSF ajax 请求中的异常处理.

In ajax requests, however, a special exception handler is needed. This is regardless of whether you use listener attribute of <f:ajax> or not. For explanation and an example, head to Exception handling in JSF ajax requests.

这篇关于action 和 actionListener 的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆