没有调用commandButton/commandLink/ajax动作/监听器方法或没有设置/更新输入值

有时,当使用<h:commandLink><h:commandButton><f:ajax>时,与标记关联的actionactionListenerlistener方法根本没有被调用。或者,bean属性不会被提交的UIInput值更新。

可能的原因和解决方法是什么?

225342 次浏览

简介

每当一个UICommand组件(<h:commandXxx><p:commandXxx>等)未能调用相关的操作方法,或一个UIInput组件(<h:inputXxx><p:inputXxxx>等)未能处理提交的值和/或更新模型值,并且你在服务器日志中没有看到任何可google的异常和/或警告,也不是当你根据JSF ajax请求中的异常处理配置ajax异常处理程序时,也不是当你在web.xml中设置以下上下文参数时,

<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>

并且在浏览器的JavaScript控制台中也没有看到任何可搜索的错误和/或警告(在Chrome/Firefox23+/IE9+中按F12打开web开发人员工具集,然后打开控制台选项卡),然后通过下面的可能原因列表进行工作。

可能的原因

  1. UICommandUIInput组件必须放在UIForm组件中,例如<h:form>(因此不是普通的HTML <form>),否则不能向服务器发送任何东西。UICommand组件也不能有type="button"属性,否则它将是一个死按钮,只对JavaScript onclick有用。参见如何发送表单输入值和调用JSF bean中的方法& lt; h: commandButton>不发起回发

  2. 不能将多个UIForm组件嵌套在一起。这在HTML中是非法的。浏览器行为未指定。注意包含文件!你可以并行使用UIForm组件,但是它们在提交时不会相互处理。你也应该注意“神的形式”;反模式;确保你不会无意中以同样的形式处理/验证所有其他(不可见的)输入(例如,有一个隐藏的对话框,需要以同样的形式输入)。另见如何使用<h:form>在JSF页面?单形式?多种形式?嵌套形式?

  3. No UIInput值验证/转换错误应该发生。你可以使用<h:messages>来显示任何特定于输入的<h:message>组件无法显示的消息。不要忘记在<f:ajax render>中包含<h:messages>id(如果有的话),这样它也会在ajax请求时被更新。另见当按下p:commandButton时,h:messages不显示消息

  4. 如果UICommandUIInput组件被放置在一个迭代组件中,如<h:dataTable><ui:repeat>等,那么你需要确保在表单提交请求的应用请求值阶段,迭代组件的value被完全相同地保留。JSF将对其进行重复,以找到所单击的链接/按钮和提交的输入值。将bean放入视图范围和/或确保在bean的@PostConstruct中加载数据模型(因此不是在getter方法中!)应该可以修复它。另见我应该如何以及何时从数据库h:dataTable加载模型

  5. 如果UICommandUIInput组件包含在诸如<ui:include src="#{bean.include}">这样的动态源中,那么你需要确保在表单提交请求的视图构建期间保留完全相同的#{bean.include}值。JSF将在构建组件树期间重新执行它。将bean放入视图范围和/或确保在bean的@PostConstruct中加载数据模型(因此不是在getter方法中!)应该可以修复它。另见如何ajax刷新动态包括导航菜单内容?(JSF SPA)

  6. 在表单提交请求的应用请求值阶段,组件及其所有父组件的rendered属性以及任何父组件<c:if>/<c:when>test属性不应该计算为false。JSF将重新检查它,作为防止篡改/黑客请求的一部分。将负责条件的变量存储在@ViewScoped bean中,或者确保在@RequestScoped bean的@PostConstruct中正确地预初始化了条件,应该可以修复它。这同样适用于组件的disabledreadonly属性,在应用请求值阶段,它们不应该计算为test0。参见test1, test2, test3和test4

  7. UICommand组件的onclick属性和UIForm组件的onsubmit属性不应该返回false或导致JavaScript错误。在<h:commandLink><f:ajax>的情况下,在浏览器的JS控制台中也应该没有可见的JS错误。通常在谷歌上搜索准确的错误信息就会得到答案。另见手动添加/加载带有PrimeFaces的jQuery会导致Uncaught TypeErrors

  8. 如果你通过JSF 2使用Ajax。x <f:ajax>或例如PrimeFaces <p:commandXxx>,确保你在主模板中有一个<h:head>而不是<head>。否则,JSF将无法自动包含包含Ajax函数的必要JavaScript文件。这将导致JavaScript错误,如“mojarra is not defined"或“PrimeFaces is not defined”;在浏览器的JS控制台。另见h:commandLink actionlistener在与f:ajax和ui:repeat一起使用时不被调用

  9. 如果你正在使用Ajax,并且提交的值最终是null,那么确保感兴趣的UIInputUICommand组件被<f:ajax execute>或例如<p:commandXxx process>覆盖,否则它们将不会被执行/处理。另见当添加<f:ajax>& lt; h: commandButton>理解PrimeFaces处理/更新和JSF f:ajax执行/呈现属性

  10. 如果提交的值最终仍然是null,并且您正在使用CDI来管理bean,那么请确保从正确的包导入范围注释,否则CDI将默认为@Dependent,这将在EL表达式的每次计算时有效地重新创建bean。参见@SessionScoped bean失去作用域并一直被重新创建,字段变为nullJSF 2应用程序中默认的托管Bean作用域是什么?

  11. 如果带有UICommand按钮的<h:form>的父元素事先被来自同一页面中另一个表单的ajax请求渲染/更新,那么在JSF 2.2或更老版本中,第一个动作总是会失败。第二个和后续的操作将起作用。这是由视图状态处理中的错误引起的,该错误报告为JSF规范第790版,目前在JSF 2.3中已修复。对于较旧的JSF版本,你需要显式地在<f:ajax>render中指定<h:form>的ID。另见h:commandButton/h:commandLink在第一次点击时不起作用,只在第二次点击时起作用

  12. 如果<h:form>为了支持文件上传而设置了enctype="multipart/form-data",那么你需要确保你使用的至少是JSF 2.2,或者负责解析多部分/表单数据请求的servlet过滤器配置正确,否则FacesServlet将最终没有得到任何请求参数,从而无法应用请求值。如何配置这样的过滤器取决于所使用的文件上传组件。对于Tomahawk <t:inputFileUpload>,检查这个答案,对于PrimeFaces <p:fileUpload>,检查这个答案。或者,如果您实际上根本不上传文件,则完全删除该属性。

  13. 确保actionListenerActionEvent参数是javax.faces.event.ActionEvent,因此不是java.awt.event.ActionEvent,这是大多数ide建议的第一个自动补全选项。如果你使用actionListener="#{bean.method}",没有参数也是错误的。如果你不想在你的方法中有参数,使用actionListener="#{bean.method()}"。或者你实际上想使用action而不是actionListener。另见action和actionListener的区别

  14. 确保请求-响应链中没有PhaseListener或任何EventListener改变JSF生命周期以跳过调用动作阶段,例如调用FacesContext#renderResponse()FacesContext#responseComplete()

  15. 确保在同一个请求-响应链中没有FilterServlet以某种方式阻止了对FacesServlet的请求。例如,登录/安全过滤器,如Spring security。特别是在ajax请求中,默认情况下最终根本没有UI反馈。另见Spring Security 4和PrimeFaces 5 AJAX请求处理

  16. 如果你正在使用PrimeFaces <p:dialog><p:overlayPanel>,那么确保它们有自己的<h:form>。因为,这些组件在默认情况下被JavaScript重新定位到HTML <body>的末尾。因此,如果它们最初位于<form>中,那么它们现在将不再位于<form>中。另见P:命令按钮的动作不'在P:对话框

  17. 框架错误。例如,RichFaces有一个&;__abc3 &;当使用带有defaultLabel属性的rich:calendar UI元素时(或者,在某些情况下,使用rich:placeholder子元素)。此错误阻止在没有为日历日期设置值时调用bean方法。跟踪框架错误可以从一个简单的工作示例开始,然后重新构建页面,直到发现错误。

调试提示

如果您仍然被困住了,现在是调试的时候了。在客户端,在web浏览器中按F12打开web开发人员工具集。单击控制台选项卡,以便查看JavaScript控制台。它应该没有任何JavaScript错误。下面的截图是一个来自Chrome的例子,它演示了在没有声明<h:head>的情况下提交一个启用<f:ajax>的按钮(如上面的第7点所述)。

js console

单击网络选项卡查看HTTP流量监视器。提交表单并调查请求头和表单数据以及响应体是否符合预期。下面的截图是一个来自Chrome的例子,它演示了一个成功的ajax提交一个简单的表单与单个<h:inputText>和单个<h:commandButton><f:ajax execute="@form" render="@form">

network monitor

(警告:当您在生产环境中发布来自HTTP请求头的截图时,请确保您在截图中扰乱/混淆任何会话cookie,以避免会话劫持攻击!)

在服务器端,确保服务器是以调试模式启动的。在JSF组件的方法中放置一个调试断点,您希望在处理表单提交期间调用该方法。例如,对于UICommand组件,它将是UICommand#queueEvent(),对于UIInput组件,它将是UIInput#validate()。只需逐步执行代码并检查流和变量是否符合预期。下面的截图是一个来自Eclipse调试器的示例。

调试服务器

如果你的h:commandLinkh:dataTable中,则有另一个原因导致h:commandLink可能无法工作:

绑定到h:dataTable的底层数据源也必须在单击链接时触发的第二个JSF-Lifecycle中可用。

因此,如果底层数据源是请求作用域,h:commandLink将不起作用!

虽然我的答案不是100%适用,但大多数搜索引擎都会把它作为第一个搜索结果,但我还是决定把它贴出来:

如果你正在使用PrimeFaces(或一些类似的API) p:commandButtonp:commandLink,很可能你已经忘记显式地将process="@this"添加到命令组件中。

正如PrimeFaces用户指南在3.18节中所述,processupdate的默认值都是@form,这与普通JSF f:ajax或RichFaces的默认值截然相反,它们分别是execute="@this"render="@none"

只是我花了很长时间才发现。(…而且我认为使用与JSF不同的默认值是相当不聪明的!)

我自己也遇到了这个问题,并发现了这个问题的另一个原因。 如果您的支持bean中没有*.xhtml中使用的属性的setter方法,则该操作将不会被调用

我想再提一件关于Primefaces的p:commandButton!

当你使用p:commandButton来执行需要在服务器上执行的操作时,你不能使用type="button",因为这是为按钮准备的,它用于执行自定义javascript,而不会向服务器发出ajax/非ajax请求。

为此,你可以不使用type属性(默认值是"submit"),也可以显式使用type="submit"

希望这能帮助到一些人!

我最近遇到了一个问题,在使用IBM Extended Faces Components的JSF 1.2应用程序中没有调用uiccommand。

我在数据表的一行(扩展版本,所以<hx:datatable>)上有一个命令按钮,UICommand不会从表中的某些行触发(不会触发的行是大于默认行显示大小的行)。

我有一个下拉组件,用于选择要显示的行数。支持该字段的值在RequestScope中。表本身的数据类型是ViewScope(实际上,暂时在SessionScope中)。

如果通过绑定到数据表的rows属性的控件来增加行显示,则由于此更改而显示的任何行在单击时都不能触发uiccommand。

将此属性置于与表数据本身相同的作用域中可以解决这个问题。

我认为这在上面的balusc# 4中有所暗示,但不仅表值需要为View或Session范围,而且还需要控制表上显示的行数的属性。

我也遇到过这个问题,在打开浏览器的web控制台后才真正开始研究根本原因。在此之前,我无法得到任何错误消息(即使是<p:messages>)。web控制台显示从<h:commandButton type="submit" action="#{myBean.submit}">返回的HTTP 405状态码。

在我的例子中,我混合了通过Auth0提供OAuth身份验证的普通HttpServlet和执行应用程序视图和业务逻辑的JSF facet和bean。

一旦我重构了web.xml,并删除了一个中间人servlet,它就“神奇地”工作了。

总之,问题是中间人servlet使用RequestDispatcher.forward(…)从HttpServlet环境重定向到JSF环境,而在此之前调用的servlet使用HttpServletResponse.sendRedirect(…)重定向。

基本上,使用sendRedirect()允许JSF“容器”获得控制,而RequestDispatcher.forward()显然不能。

我不知道为什么facelet能够访问bean属性,但不能设置它们,这显然是为了消除servlet和JSF的混合,但我希望这可以帮助人们避免长时间的头到表的碰撞。

我有很多有趣的调试问题,其中<h:commandLink>的行动在richfaces datatable拒绝发射。这张桌子曾经在某个时候工作过,但没有明显的原因就停了下来。我想尽一切办法,只发现我的rich:datatable使用了错误的rowKeyConverter,它返回了richfaces愉快地用作行键的空值。这阻止了我的<h:commandLink>操作被调用。

还有一种可能性:如果症状是第一次调用有效,但随后的调用无效,那么您可能使用的是PrimeFaces 3。没有发送ViewState. x使用JSF 2.2,详细说明如下:

我修复了我的问题,放置:

<h:commandButton class="btn btn-danger" value = "Remove" action="#{deleteEmployeeBean.delete}"></h:commandButton>

:

<h:form>
<h:commandButton class="btn btn-danger" value = "Remove" action="#{deleteEmployeeBean.delete}"></h:commandButton>
</h:form>
<ui:composition>
<h:form id="form1">
<p:dialog id="dialog1">
<p:commandButton value="Save" action="#{bean.method1}" /> <!--Working-->
</p:dialog>
</h:form>


<h:form id="form2">
<p:dialog id="dialog2">
<p:commandButton value="Save" action="#{bean.method2}" /> <!--Not Working-->
</p:dialog>
</h:form>
</ui:composition>

来解决;

<ui:composition>
<h:form id="form1">
<p:dialog id="dialog1">
<p:commandButton value="Save" action="#{bean.method1}" />   <!-- Working  -->
</p:dialog>


<p:dialog id="dialog2">
<p:commandButton value="Save" action="#{bean.method2}" />   <!--Working  -->
</p:dialog>
</h:form>
<h:form id="form2">
<!-- ..........  -->
</h:form>
</ui:composition>

这就是解决方法,对我来说很管用。

<p:commandButton id="b1" value="Save" process="userGroupSetupForm"
actionListener="#{userGroupSetupController.saveData()}"
update="growl userGroupList userGroupSetupForm" />

这里,process="userGroupSetupForm"属性是Ajax调用的强制属性。actionListener从@ViewScope Bean调用一个方法。也更新咆哮消息,数据表:userGroupList和表单:userGroupSetupForm。