action和actionListener之间的区别

我的未来我决定 提交于 2020-02-27 01:43:48

actionactionListener什么区别,什么时候应该使用actionactionListener


#1楼

在调用Action并确定下一页的位置之前,将首先触发ActionListener并提供修改响应的选项。

如果您在同一页面上有多个按钮,这些按钮应该移至相同的位置,但执行的操作略有不同,则可以为每个按钮使用相同的Action,但使用不同的ActionListener处理稍微不同的功能。

这是描述关系的链接:

http://www.java-samples.com/showtutorial.php?tutorialid=605


#2楼

actionListener

如果您想执行实际业务操作之前有一个钩子请使用actionListener ,例如将其记录和/或设置其他属性(通过<f:setPropertyActionListener> ),和/或访问调用了动作(可通过ActionEvent参数获得)。 因此,纯粹是为了在调用实际业务操作之前进行准备。

默认情况下, 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+样式括号会透明地将值表达式转换为方法表达式。 另请参见ao 如果JSF不支持<f:actionListener>为何可以将它绑定到任意方法?


行动

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

action方法可以是任何有效的MethodExpression ,也可以是使用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进行解释? 并且应该解决为

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

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


f:ajax监听器

自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一样, f:ajax listener器不支持返回导航结果。

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

有关executerender属性的说明,请转到了解PrimeFaces流程/更新和JSF f:ajax执行/渲染属性


调用顺序

始终以与在视图中声明并附加到组件的顺序相同的顺序在action 之前调用actionListener 。 始终任何操作侦听器之前调用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方法返回同一页面,那么那是一个不好的选择。 与某些IDE通过EL验证让您相信的相反, action方法也可以完美地返回void 。 请注意, PrimeFaces展示示例在所有地方都散布着这种actionListener 。 这确实是错误的。 不要以此为借口自己做。

但是,在ajax请求中,需要特殊的异常处理程序。 这与是否使用<f:ajax> listener属性无关。 有关说明和示例,请转到JSF ajax request中的异常处理


#3楼

正如BalusC指出的actionListener ,默认情况下, actionListener吞下异常,但是在JSF 2.0中,还有更多的东西。 即,它不仅吞咽和记录日志,而且实际上发布了异常。

这是通过这样的调用发生的:

context.getApplication().publishEvent(context, ExceptionQueuedEvent.class,                                                          
    new ExceptionQueuedEventContext(context, exception, source, phaseId)
);

此事件的默认侦听器是ExceptionHandler ,对于Mojarra它将设置为com.sun.faces.context.ExceptionHandlerImpl 。 此实现基本上将抛出任何异常,除非它涉及记录的AbortProcessingException。 ActionListener将客户代码引发的异常包装在AbortProcessingException中,该异常解释了为什么始终记录这些异常。

但是,可以在faces-config.xml中使用自定义实现替换此ExceptionHandler

<exception-handlerfactory>
   com.foo.myExceptionHandler
</exception-handlerfactory>

除了全局监听之外,单个bean也可以监听这些事件。 以下是这一概念的证明:

@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");
    }

}

(请注意,这不是通常应该编写侦听器的方式,这只是出于演示目的!)

从Facelet这样调用:

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

将导致显示错误页面。


#4楼

TL; DR

ActionListener (可以有多个)以action之前注册的顺序执行

长答案

业务action通常会调用EJB服务,并且如果不是您正在执行的actionListener则业务action通常会调用最终服务和/或导航到其他视图actionListener更适合,即当用户与组件交互时,例如h:commandButtonh:link可以通过在UI Component的actionListener属性中传递托管bean方法的名称来实现,也可以通过实现ActionListener接口并将实现类名称传递给UI Component的actionListener属性来进行处理。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!