提问人:Muhammad Hewedy 提问时间:1/23/2010 最后编辑:KukeltjeMuhammad Hewedy 更新时间:9/15/2023 访问量:230459
commandButton/commandLink/ajax 操作/侦听器方法未调用或输入值未设置/更新
commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated
问:
有时,当使用 、 或 、 或与标记关联的方法时,根本不会调用。或者,不会使用提交的值更新 Bean 属性。<h:commandLink>
<h:commandButton>
<f:ajax>
action
actionListener
listener
UIInput
造成这种情况的可能原因和解决方案是什么?
答:
介绍
每当组件 (, , 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 开发人员工具集,然后打开控制台选项卡),然后完成以下可能原因列表。
可能原因
UICommand
并且组件必须放置在组件内部,例如 (因此不是纯 HTML ),否则无法向服务器发送任何内容。 组件也不能有属性,否则它将是一个死按钮,只对 JavaScript 有用。另请参阅如何在 JSF bean 中发送表单输入值和调用方法和 <h:commandButton> 不启动回发。UIInput
UIForm
<h:form>
<form>
UICommand
type="button"
onclick
不能将多个组件相互嵌套。这在 HTML 中是非法的。未指定浏览器行为。注意包含文件!您可以并行使用组件,但它们在提交期间不会相互处理。您还应该注意“上帝形态”反模式;确保您不会无意中以完全相同的形式处理/验证所有其他(不可见的)输入(例如,有一个隐藏的对话框,其中包含相同形式的所需输入)。另请参阅如何在 JSF 页面中使用 <h:form>?单一形式?多种形式?嵌套形式?.
UIForm
UIForm
不应发生任何值验证/转换错误。您可以使用它来显示任何特定于输入的组件未显示的任何消息。不要忘记在 中包含 of(如果有的话),以便它也会在 ajax 请求中更新。另请参阅 h:messages 在按下 p:commandButton 时不显示消息。
UIInput
<h:messages>
<h:message>
id
<h:messages>
<f:ajax render>
如果 或 组件被放置在迭代组件(如 、 等)中,则需要确保在表单提交请求的“应用请求值”阶段保留完全相同的迭代组件。JSF 将重申它以查找单击的链接/按钮和提交的输入值。将 Bean 放在视图范围内和/或确保将数据模型加载到 Bean 中(因此不是在 getter 方法中!)应该可以修复它。另请参阅应如何以及何时应从数据库加载 JSF dataTable 的模型。
UICommand
UIInput
<h:dataTable>
<ui:repeat>
value
@PostConstruct
如果 或组件包含在动态源(如 )中,则需要确保在表单提交请求的视图构建期间保留完全相同的值。JSF 将在构建组件树期间重新执行它。将 Bean 放在视图范围内和/或确保将数据模型加载到 Bean 中(因此不是在 getter 方法中!)应该可以修复它。参见 如何通过导航菜单ajax刷新动态包含内容?(JSF SPA)。
UICommand
UIInput
<ui:include src="#{bean.include}">
#{bean.include}
@PostConstruct
组件及其所有父项的属性以及任何父项的属性 / 不应在表单提交请求的应用请求值阶段计算为。JSF 将重新检查它,作为防止篡改/黑客攻击请求的一部分。将负责条件的变量存储在 Bean 中,或者确保正确地预初始化 Bean 中的条件应该可以修复它。这同样适用于组件的 和 属性,在应用请求值阶段不应计算到这些属性。另请参阅 JSF CommandButton 操作未调用,未处理条件呈现组件中的表单提交,h:commandButton 在我将它包装在呈现的 <h:panelGroup 中后不起作用>以及强制 JSF 无论如何都处理、验证和更新只读/禁用的输入组件
rendered
test
<c:if>
<c:when>
false
@ViewScoped
@PostConstruct
@RequestScoped
disabled
readonly
true
组件的属性和组件的属性不应返回或导致 JavaScript 错误。在浏览器的 JS 控制台中应该没有可见的 JS 错误。通常,谷歌搜索确切的错误消息已经会给你答案。另请参阅使用 PrimeFaces 手动添加/加载 jQuery 会导致未捕获的 TypeErrors。
onclick
UICommand
onsubmit
UIForm
false
<h:commandLink>
<f:ajax>
如果您通过 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>
如果您使用的是 Ajax,并且提交的值最终为 ,请确保感兴趣的 和 组件被 或 覆盖,否则它们将不会被执行/处理。另请参阅将 <f:ajax> 添加到 <h:commandButton 时,模型中未更新提交的表单值>和了解 PrimeFaces process/update 和 JSF f:ajax execute/render 属性。
null
UIInput
UICommand
<f:ajax execute>
<p:commandXxx process>
如果提交的值最终仍为 ,并且您正在使用 CDI 来管理 bean,请确保从正确的包中导入范围注释,否则 CDI 将默认为在每次计算 EL 表达式时有效地重新创建 bean。另请参阅 @SessionScoped Bean 失去作用域并一直重新创建,字段变为 null 和 JSF 2 应用程序中的缺省托管 Bean 作用域是什么?
null
@Dependent
如果 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>
如果 has 设置为支持文件上传,那么您需要确保至少使用 JSF 2.2,或者负责解析 multipart/form-data 请求的 servlet 过滤器已正确配置,否则最终将根本没有获得任何请求参数,因此无法应用请求值。如何配置此类筛选器取决于所使用的文件上传组件。对于战斧,请检查此答案,对于 PrimeFaces,请检查此答案。或者,如果您实际上根本没有上传文件,则完全删除该属性。
<h:form>
enctype="multipart/form-data"
FacesServlet
<t:inputFileUpload>
<p:fileUpload>
确保 的参数是 和 not ,这是大多数 IDE 建议的第一个自动完成选项。如果你使用 .如果方法中不需要参数,请使用 .或者,也许您实际上想使用 而不是 .另请参阅 action 和 actionListener 之间的差异。
ActionEvent
actionListener
jakarta.faces.event.ActionEvent
java.awt.event.ActionEvent
actionListener="#{bean.method}"
actionListener="#{bean.method()}"
action
actionListener
确保请求-响应链中 no 或 any 更改了 JSF 生命周期以跳过调用操作阶段,例如,调用或 .
PhaseListener
EventListener
FacesContext#renderResponse()
FacesContext#responseComplete()
确保没有或在同一请求-响应链中以某种方式阻止了请求。例如,登录/安全过滤器,例如 Spring Security。特别是在 ajax 请求中,默认情况下,这些请求最终根本没有 UI 反馈。另请参阅 Spring Security 4 和 PrimeFaces 5 AJAX 请求处理。
Filter
Servlet
FacesServlet
如果您使用的是 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>
单击“网络”选项卡以查看 HTTP 流量监视器。提交表单并调查请求标头和表单数据以及响应正文是否符合预期。下面的屏幕截图是 Chrome 中的一个示例,它演示了带有 single 的简单表单和带有 .<h:inputText>
<h:commandButton>
<f:ajax execute="@form" render="@form">
(警告:当您从生产环境发布上述 HTTP 请求标头的屏幕截图时,请确保对屏幕截图中的任何会话 cookie 进行加扰/混淆,以避免会话劫持攻击!
在服务器端,确保服务器以调试模式启动。将调试断点放在感兴趣的 JSF 组件的方法中,您希望在处理表单提交期间调用该断点。例如,如果是组件,则为 UICommand#queueEvent(),
如果是组件,则为 UIInput#validate()。
只需逐步执行代码并检查流程和变量是否符合预期即可。下面的屏幕截图是 Eclipse 调试器的一个示例。UICommand
UIInput
评论
如果你在里面,还有另一个原因可能导致它不起作用:h:commandLink
h:dataTable
h:commandLink
绑定到 的基础数据源也必须在单击链接时触发的第二个 JSF 生命周期中可用。h:dataTable
因此,如果基础数据源是请求范围的,则不起作用!h:commandLink
评论
虽然我的答案不是 100% 适用,但大多数搜索引擎都认为这是第一个命中,我决定毫不犹豫地发布它:
如果您使用的是 PrimeFaces(或一些类似的 API)或 ,则可能是您忘记显式添加到命令组件中。p:commandButton
p:commandLink
process="@this"
正如《PrimeFaces 用户指南》第 3.18 节所述,和 的默认值是 both ,这与普通 JSF 或 RichFaces 的默认值几乎相反,它们分别是 和。process
update
@form
f:ajax
execute="@this"
render="@none"
我花了很长时间才知道。(...而且我认为使用与 JSF 不同的默认值是相当不聪明的!
评论
process
@form
@this
p:commandButton
process="@this"
process="@this"
<p:messages autoUpdate="true">
我自己遇到了这个问题,并找到了这个问题的另一个原因。 如果 *.xhtml 中使用的属性的支持 Bean 中没有 setter 方法,则根本不会调用该操作。
评论
PropertyNotWritableException
我还要提一件事,与Primefaces有关!p:commandButton
当您将 用于需要在服务器上完成的操作时,您不能使用,因为这是用于执行自定义 javascript 而不会对服务器产生 ajax/non-ajax 请求的按钮。p:commandButton
type="button"
为此,您可以分配该属性(默认值为 ),也可以显式使用 .type
"submit"
type="submit"
希望这对某人有所帮助!
评论
p:commandButton
type
button
Primefaces
我最近遇到了一个问题,即 UICommand 无法在使用 IBM Extended Faces 组件的 JSF 1.2 应用程序中调用。
我在数据表的一行上有一个命令按钮(扩展版本,所以),UICommand 不会从表中的某些行触发(不会触发的行是大于默认行显示大小的行)。<hx:datatable>
我有一个下拉组件,用于选择要显示的行数。支持此字段的值位于 中。支持表本身的数据在某种程度上(实际上,暂时在 )。RequestScope
ViewScope
SessionScope
如果通过控件增加行显示,该控件的值也绑定到数据表的属性,则由于此更改而显示的任何行都不会在单击时触发 UICommand。rows
将此属性放在与表数据本身相同的作用域中可以解决此问题。
我认为这在上面的 BalusC #4 中有所暗示,但不仅表值需要是 View 或 Session 范围,还需要控制该表上显示的行数的属性。
我也遇到了这个问题,直到打开浏览器的 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 的混合而尖叫,但我希望这能帮助人们避免数小时的头到桌的碰撞。
我在调试一个问题时玩得很开心,其中 a 的操作拒绝开火。这张桌子曾经在某个时候工作过,但无缘无故地停止了。我不遗余力,却发现我使用了错误的空值,富人很高兴地将其用作行键。这阻止了我的操作被调用。<h:commandLink>
richfaces
datatable
rich:datatable
rowKeyConverter
<h:commandLink>
还有一种可能性:如果症状是第一次调用有效,但后续调用不起作用,则您可能正在将 PrimeFaces 3.x 与 JSF 2.2 一起使用,详见此处:未发送 ViewState。
我解决了放置以下文件的问题:
<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” atrribute 对于 Ajax 调用是必需的。actionListener 正在从 @ViewScope Bean 调用方法。同时更新咆哮消息,Datatable:userGroupList 和 Form:userGroupSetupForm。
评论
对我有用的解决方案是将 <p:commandButton>放在表单内或表单数据所在的内部,例如在 <p:outputPanel 中> 中表示 intance。
评论