commandButton/commandLink/ajax 操作/侦听器方法未调用或输入值未设置/更新

commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated

提问人:Muhammad Hewedy 提问时间:1/23/2010 最后编辑:KukeltjeMuhammad Hewedy 更新时间:9/15/2023 访问量:230459

问:

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

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

JSF JSF-2 操作 CommandButton CommandLink

评论


答:

721赞 BalusC 1/23/2010 #1

介绍

每当组件 (, , etc) 无法调用关联的操作方法,或者组件 (, , etc) 无法处理提交的值和/或更新模型值时,并且您在服务器日志中看不到任何可搜索的异常和/或警告时,当您根据 JSF ajax 请求中的异常处理配置 ajax 异常处理程序时, 也不是当您在 ,UICommand<h:commandXxx><p:commandXxx>UIInput<h:inputXxx><p:inputXxxx>web.xml

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

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

可能原因

  1. UICommand并且组件必须放置在组件内部,例如 (因此不是纯 HTML ),否则无法向服务器发送任何内容。 组件也不能有属性,否则它将是一个死按钮,只对 JavaScript 有用。另请参阅如何在 JSF bean 中发送表单输入值和调用方法<h:commandButton> 不启动回发UIInputUIForm<h:form><form>UICommandtype="button"onclick

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

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

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

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

  6. 组件及其所有父项的属性以及任何父项的属性 / 不应在表单提交请求的应用请求值阶段计算为。JSF 将重新检查它,作为防止篡改/黑客攻击请求的一部分。将负责条件的变量存储在 Bean 中,或者确保正确地预初始化 Bean 中的条件应该可以修复它。这同样适用于组件的 和 属性,在应用请求值阶段不应计算到这些属性。另请参阅 JSF CommandButton 操作未调用未处理条件呈现组件中的表单提交,h:commandButton 在我将它包装在呈现的 <h:panelGroup 中后不起作用>以及强制 JSF 无论如何都处理、验证和更新只读/禁用的输入组件renderedtest<c:if><c:when>false@ViewScoped@PostConstruct@RequestScopeddisabledreadonlytrue

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

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

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

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

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

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

  13. 确保 的参数是 和 not ,这是大多数 IDE 建议的第一个自动完成选项。如果你使用 .如果方法中不需要参数,请使用 .或者,也许您实际上想使用 而不是 .另请参阅 action 和 actionListener 之间的差异ActionEventactionListenerjakarta.faces.event.ActionEventjava.awt.event.ActionEventactionListener="#{bean.method}"actionListener="#{bean.method()}"actionactionListener

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

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

  16. 如果您使用的是 PrimeFaces 或 ,请确保它们有自己的 .因为,这些组件默认被 JavaScript 重新定位到 HTML 的末尾。因此,如果他们最初坐在 里面,那么他们现在将不再坐在 .参见 p:commandbutton 操作在 p:dialog 中不起作用<p:dialog><p:overlayPanel><h:form><body><form><form>

调试提示

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

js console

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

network monitor

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

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

debug server

评论

1赞 Paulo Guedes 10/7/2010
你的第二点让我思考了很长一段时间。我刚刚发现主文件中的 f:view 标签是我大多数问题的原因。可能是因为它呈现了一种形式,对吧?
2赞 Lucas 9/17/2011
@pauloguedes我找不到任何声明f:view呈现表单的内容。我的理解是它只是一个容器。根据我的经验,f:view不会呈现任何元素。
0赞 Lucas 9/17/2011
@balusc 对第 4 点进行一些澄清,如果 commandLink 不在 dataTable 本身中,它仍然重要吗?
0赞 merveotesi 2/10/2013
谢谢,重点就是重点:将 Bean 放在视图范围内和/或确保在 Bean 的(post)构造函数中加载数据模型(因此不是在 getter 方法中!)应该可以修复它。
2赞 BalusC 7/23/2015
@Kukeltje:这会引发 EL 异常(答案中的第 1 段已经涵盖了)
56赞 jbandi 11/9/2010 #2

如果你在里面,还有另一个原因可能导致它不起作用:h:commandLinkh:dataTableh:commandLink

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

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

评论

2赞 jbandi 11/9/2010
好吧,这对我来说并不完全清楚。无论如何,我希望我的答案是有帮助的,因为至少在我的情况下,我没有明确地处理 UICommand/UIData。“解决方案”是将后备 Bean 从请求范围提升到会话范围......
1赞 Zack Macomber 12/11/2012
我第二个詹斯评论...将我的 RequestScoped bean 设置为 SessionScoped 对我的 dataTable 产生了影响 - 谢谢
32赞 Kawu 1/4/2013 #3

虽然我的答案不是 100% 适用,但大多数搜索引擎都认为这是第一个命中,我决定毫不犹豫地发布它:

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

正如《PrimeFaces 用户指南》第 3.18 节所述,和 的默认值是 both ,这与普通 JSF 或 RichFaces 的默认值几乎相反,它们分别是 和。processupdate@formf:ajaxexecute="@this"render="@none"

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

评论

6赞 BalusC 1/4/2013
PrimeFaces 的默认值为 。因此,如果该操作不是以这种方式调用的,而是在使用 时调用的,那么我的答案中的第 3 点很可能适用。process@form@this
3赞 Kawu 1/4/2013
这不可能。我有一个没有调用actionListener方法,直到我添加。此外,《PrimeFaces 用户指南》明确列出了我在 3.18 和 3.19 节中提到的默认值。它在这里:primefaces.googlecode.com/files/primefaces_users_guide_3_4.pdf......也许默认值已更改?p:commandButtonprocess="@this"
8赞 BalusC 1/4/2013
这可能是文档中的错误。删除并添加(或仅读取排队但未显示的消息的服务器日志),您将看到实际上发生了转换/验证错误。process="@this"<p:messages autoUpdate="true">
0赞 Kukeltje 3/14/2020
你为什么删除这个问题 stackoverflow.com/questions/60673695/...
0赞 Kawu 3/15/2020
我以为它现在可能不会提供太多价值......我取消了删除它。
4赞 Dnavir 2/23/2013 #4

我自己遇到了这个问题,并找到了这个问题的另一个原因。 如果 *.xhtml 中使用的属性的支持 Bean 中没有 setter 方法,则根本不会调用该操作。

评论

5赞 BalusC 2/23/2013
它应该导致一个相当不言自明的.如果你没有看到它,也许你触发了一个ajax请求,而没有适当的ajax异常处理程序,但你应该在服务器日志中看到它。PropertyNotWritableException
3赞 Dnavir 2/24/2013
直到我制作了 p:commandButton 的 ajax=“false”,它才显示该异常。
0赞 exrezzo 3/15/2019
感谢上帝,你救了我的命
12赞 akelec 1/4/2015 #5

我还要提一件事,与Primefaces有关!p:commandButton

当您将 用于需要在服务器上完成的操作时,您不能使用,因为这是用于执行自定义 javascript 而不会对服务器产生 ajax/non-ajax 请求的按钮p:commandButtontype="button"

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

希望这对某人有所帮助!

评论

0赞 Uriel Arvizu 5/27/2015
这是我在我们的一个页面中的主要问题,公认的答案中没有一个点让我们更接近,你在哪里找到这些信息?
0赞 akelec 6/14/2015
好吧,我遇到过很多次这个问题,我做了研究,发现它有几个属性值,并且是一个涉及客户端的一切。在文档中很难找到它,但这里有一个链接:developer.am/primefaces/...p:commandButtontypebuttonPrimefaces
0赞 sjantke 5/4/2017
您的提交提示解决了我几天来一直面临的问题。非常感谢您的帖子!
0赞 akelec 5/4/2017
谢谢,这是我的荣幸。我特意提出这个答案,因为我们中的许多人都有这样的问题。我也失去了几天,直到意识到这是怎么回事。
4赞 Brent C 10/14/2015 #6

我最近遇到了一个问题,即 UICommand 无法在使用 IBM Extended Faces 组件的 JSF 1.2 应用程序中调用。

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

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

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

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

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

3赞 Brooks 4/12/2017 #7

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

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

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

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

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

我不知道的是为什么 facelet 能够访问 bean 属性但无法设置它们,这显然是为了取消 servlet 和 JSF 的混合而尖叫,但我希望这能帮助人们避免数小时的头到桌的碰撞。

2赞 Mustafa 5/3/2017 #8

我在调试一个问题时玩得很开心,其中 a 的操作拒绝开火。这张桌子曾经在某个时候工作过,但无缘无故地停止了。我不遗余力,却发现我使用了错误的空值,富人很高兴地将其用作行键。这阻止了我的操作被调用。<h:commandLink>richfacesdatatablerich:datatablerowKeyConverter<h:commandLink>

0赞 Dave Mulligan 8/18/2017 #9

还有一种可能性:如果症状是第一次调用有效,但后续调用不起作用,则您可能正在将 PrimeFaces 3.x 与 JSF 2.2 一起使用,详见此处:未发送 ViewState

-1赞 Georgi Peev 2/9/2019 #10

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

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

评论

1赞 Kukeltje 2/9/2019
这是 >600 个赞成答案中的 #1。无需将其写成单独的答案。
-2赞 Kenan Gökbak 7/12/2019 #11
<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>

评论

0赞 Kukeltje 7/12/2019
对不起,但以我的拙见,这完全不是真的。您有效地声明了 2 个对话框需要以自己的形式才能工作。你有 99% 的把握解决了一个不同的问题,你现在认为这是解决方案......
0赞 Kenan Gökbak 7/12/2019
这是包含的页面。也许这可能会导致问题。您应该在投票前对其进行测试。
0赞 Kukeltje 7/13/2019
不,您应该在发布之前创建一个最小的可重现示例(只有这样我才能测试)......是的,包含可能会导致对话框和表单出现问题,但问题仍然不是您似乎想要在这里解决的问题。你的第一个例子是完全没问题的,第二个例子是 100% 确定的,而不是一个不存在的问题的解决方案
0赞 Kenan Gökbak 7/13/2019
无论如何。我的应用程序工作正常。我认为对话框在表单中的位置并不重要。我必须创建第二个表单来解决另一个问题。
0赞 Kukeltje 7/13/2019
您的应用程序可能正在工作,但从原始问题和您的“解决方案”中并不清楚/可见。此外,你说_“我认为对话框在表单中的位置并不重要。“_But在你的回答中,他们在哪里似乎很重要。支持我的说法的矛盾。对不起,你的回答完全是错误的......(已经有另一张反对票)
-1赞 Rajib Kumer Ghosh 12/9/2019 #12

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

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

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

评论

0赞 Jasper de Vries 9/22/2021
这解决了什么问题?你做了什么改变来解决它?为什么您的更改解决了您的问题?你确定它没有在顶部答案中提到吗?
-1赞 Aakash Saini 3/18/2023 #13

对我有用的解决方案是将 <p:commandButton>放在表单内或表单数据所在的内部,例如在 <p:outputPanel 中> 中表示 intance。

评论

1赞 Jasper de Vries 3/18/2023
这是最重要的答案之一。