359

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

造成这种情况的可能原因和解决方案是什么?

4

12 回答 12

707

介绍

每当UICommand组件(<h:commandXxx>,<p:commandXxx>等)未能调用关联的操作方法,或UIInput组件(<h:inputXxx>,<p:inputXxxx>等)未能处理提交的值和/或更新模型值,并且您没有看到任何可谷歌搜索的异常和/或服务器日志中的警告,也不是当您根据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. UICommand并且UIInput组件必须放在UIForm组件内,例如<h:form>(因此不是纯 HTML <form>),否则无法将任何内容发送到服务器。UICommand组件也不能有type="button"属性,否则它将是一个只对 JavaScript 有用的死按钮onclick。另请参阅如何发送表单输入值并调用 JSF bean 中的方法,并且<h:commandButton> 不会启动回发

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

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

  4. 如果UICommandUIInput组件被放置在像<h:dataTable>,等迭代组件内,那么您需要确保在表单提交请求的应用请求值阶段保留<ui:repeat>完全相同的迭代组件。valueJSF 将重复它以找到单击的链接/按钮和提交的输入值。将 bean 放入视图范围和/或确保将数据模型加载到@PostConstructbean 中(因此不在 getter 方法中!)应该修复它。另请参阅如何以及何时从数据库中加载模型以获取 h:dataTable

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

  6. 在表单提交请求的应用请求值阶段,rendered组件及其所有父级的属性test以及任何父级<c:if>/的属性<c:when>不应评估。falseJSF 将重新检查它,作为防止篡改/黑客请求的一部分。将负责条件的变量存储在@ViewScopedbean 中或确保您正确地预初始化 bean 中的条件@PostConstruct应该@RequestScoped修复它。这同样适用于组件的disabled和属性,在应用请求值阶段readonly不应评估。true另请参阅未调用 JSF CommandButton 操作未处理有条件呈现的组件中的表单提交一旦我将 h:commandButton 包装在 <h:panelGroup rendering>中并强制 JSF 处理、验证和更新只读/禁用的输入组件, h:commandButton 就不起作用

  7. 组件的属性和组件的属性onclick不应返回或导致 JavaScript 错误。在浏览器的 JS 控制台中应该有或没有可见的 JS 错误。通常谷歌搜索确切的错误信息已经给你答案了。另请参阅使用 PrimeFaces 手动添加/加载 jQuery 导致 Uncaught TypeErrorsUICommandonsubmitUIFormfalse<h:commandLink><f:ajax>

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

  9. 如果您使用的是 Ajax,并且提交的值最终是null,那么请确保UIInputUICommand感兴趣的组件被<f:ajax execute>or覆盖<p:commandXxx process>,否则它们将不会被执行/处理。另请参阅将 <f:ajax> 添加到 <h:commandButton>了解 PrimeFaces 进程/更新和 JSF f:ajax 执行/渲染属性时未在模型中更新的提交表单值。

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

  11. <h:form>如果带有按钮的父级UICommand事先由来自同一页面中另一个表单的 ajax 请求呈现/更新,那么在 JSF 2.2 或更早版本中,第一个操作将始终失败。第二个和后续操作将起作用。这是由视图状态处理中的错误引起的,该错误报告为JSF 规范问题 790,目前已在 JSF 2.3 中修复。对于较旧的 JSF 版本,您需要<h:form>render. <f:ajax>另请参阅h:commandButton/h:commandLink 在第一次单击时不起作用,仅在第二次单击时起作用

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

  13. 确保ActionEvent参数 ofactionListener是 an javax.faces.event.ActionEvent而不是java.awt.event.ActionEvent,这是大多数 IDE 建议的第一个自动完成选项。如果你使用 . 没有参数也是错误的actionListener="#{bean.method}"。如果您不想在方法中使用参数,请使用actionListener="#{bean.method()}". 或者,也许您实际上想使用action而不是actionListener. 另请参阅action 和 actionListener 之间的差异

  14. 确保请求-响应链中的 noPhaseListener或 anyEventListener已更改 JSF 生命周期以跳过调用操作阶段,例如调用FacesContext#renderResponse()FacesContext#responseComplete()

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

  16. 如果您使用 PrimeFaces<p:dialog>或 a <p:overlayPanel>,请确保它们有自己的<h:form>. 因为,这些组件在默认情况下被 JavaScript 重新定位到 HTML 的末尾<body>。所以,如果他们原本坐在 a 里面<form>,那么他们现在就不会再坐在 a里面了<form>。另请参阅p:commandbutton 操作在 p:dialog 中不起作用

  17. 框架中的错误。例如,RichFaces在使用带有属性(或者在某些情况下是子元素)的UI 元素时会出现“转换错误” 。当没有为日历日期设置值时,此错误会阻止调用 bean 方法。跟踪框架错误可以通过从一个简单的工作示例开始并构建页面备份直到发现错误来完成。rich:calendardefaultLabelrich:placeholder

调试提示

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

js控制台

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

网络监视器

(警告:当您从生产环境中发布来自上述 HTTP 请求标头的屏幕截图时,请确保您对屏幕截图中的任何会话 cookie 进行加扰/混淆以避免会话劫持攻击!)

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

调试服务器

于 2010-01-22T20:13:22.793 回答
55

如果您h:commandLink在其中,则可能无法正常工作h:dataTable的另一个原因是:h:commandLink

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

因此,如果底层数据源是请求范围的,则h:commandLink不起作用!

于 2010-11-08T22:25:06.073 回答
30

虽然我的答案不是 100% 适用,但大多数搜索引擎认为这是第一次点击,但我还是决定发布它:

如果您使用PrimeFaces(或一些类似的 API)p:commandButtonp:commandLink,您可能忘记显式添加process="@this"到您的命令组件。

正如 PrimeFaces 用户指南在第 3.18 节中所述,process和的默认值update都是@form,这与您可能期望的普通 JSFf:ajax或 RichFaces 的默认值(分别是execute="@this"和)完全相反render="@none"

我花了很长时间才知道。(......而且我认为使用与 JSF 不同的默认值是相当不明智的!)

于 2013-01-03T18:51:03.647 回答
10

我还要提到一件与 Primefaces 相关的事情p:commandButton

当您将 ap:commandButton用于需要在服务器上完成的操作时,您不能使用type="button"它,因为这是用于执行自定义 javascript 而不会导致向服务器发出 ajax/非 ajax 请求的按钮

为此,您可以分配type属性(默认值为"submit"),也可以显式使用type="submit".

希望这会对某人有所帮助!

于 2015-01-03T19:15:10.743 回答
3

我自己陷入了这个问题,并找到了导致此问题的另一个原因。如果您的后备 bean 中没有用于 *.xhtml 中使用的属性的 setter 方法,则根本不会调用该操作。

于 2013-02-23T10:55:59.083 回答
3

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

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

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

如果通过控制哪个值也绑定到数据表的rows属性来增加行显示,则由于此更改而显示的所有行都不会在单击时触发 UICommand。

将此属性放置在与表数据本身相同的范围内解决了该问题。

我认为这在上面的 BalusC #4 中有所提及,但不仅表值需要在视图或会话范围内,而且控制在该表上显示的行数的属性也是如此。

于 2015-10-13T18:23:29.220 回答
2

我也遇到了这个问题,只是在打开浏览器的 Web 控制台后才真正开始研究根本原因。在那之前,我无法收到任何错误消息(即使使用<p:messages>)。Web 控制台显示从<h:commandButton type="submit" action="#{myBean.submit}">.

就我而言,我混合了通过 Auth0 和 JSF facelets 提供 OAuth 身份验证的 vanilla HttpServlet,以及执行我的应用程序视图和业务逻辑的 bean。

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

归根结底,问题在于中间人 servlet 使用 RequestDispatcher.forward(...) 从 HttpServlet 环境重定向到 JSF 环境,而在它之前调用的 servlet 使用 HttpServletResponse.sendRedirect(.. .)。

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

我不知道为什么 facelet 能够访问 bean 属性但无法设置它们,这显然是为了取消 servlet 和 JSF 的混合,但我希望这可以帮助某人避免数小时的头疼-敲桌子。

于 2017-04-11T16:11:51.717 回答
1

<h:commandLink>我在调试 a的操作richfaces datatable拒绝触发的问题时获得了很多乐趣。该表曾经在某个时候工作,但无缘无故停止了。我不遗余力,只是发现我rich:datatable使用了错误rowKeyConverter的返回空值,richfaces 很乐意用作行键。这阻止了我的<h:commandLink>动作被调用。

于 2017-05-02T19:06:38.277 回答
0

还有一种可能性:如果症状是第一次调用有效,但后续调用无效,则您可能正在使用带有 JSF 2.2 的 PrimeFaces 3.x,详情如下:No ViewState is sent

于 2017-08-17T22:22:41.163 回答
-1

我解决了放置以下问题的问题:

<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>
于 2019-02-08T19:38:47.367 回答
-1

这是解决方案,对我有用。

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

在这里, process="userGroupSetupForm" 属性对于 Ajax 调用是必需的。actionListener 正在从 @ViewScope Bean 调用一个方法。同时更新咆哮消息,Datatable:userGroupList 和 Form:userGroupSetupForm。

于 2019-12-09T07:05:14.060 回答
-2
<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>
于 2019-07-12T11:51:14.127 回答