为什么第一个AJAX调用会重置我的视图参数?

为什么第一个AJAX调用会重置我的视图参数?,ajax,jsf,mojarra,jsf-2.3,Ajax,Jsf,Mojarra,Jsf 2.3,我不明白为什么第一个ajax调用会导致再次调用视图参数的setter,而随后的每个调用都不会再次调用setter 我有以下简单的视图bean: 封装测试; 导入java.io.Serializable; 导入javax.faces.view.ViewScoped; 导入javax.inject.Named; @命名 @视域 公共类TestController实现可序列化{ 私有静态最终长serialVersionUID=1L; 字符串参数; 公共字符串getParam(){ 返回参数; } 公共

我不明白为什么第一个ajax调用会导致再次调用视图参数的setter,而随后的每个调用都不会再次调用setter

我有以下简单的视图bean:

封装测试;
导入java.io.Serializable;
导入javax.faces.view.ViewScoped;
导入javax.inject.Named;
@命名
@视域
公共类TestController实现可序列化{
私有静态最终长serialVersionUID=1L;
字符串参数;
公共字符串getParam(){
返回参数;
}
公共void setParam(字符串参数){
System.out.println(“参数设置为”+param);
this.param=param;
}
}
我还有一个非常基本的.xhtml页面,它只包含一个按钮:


现在,当测试此页面时,我调用
https://localhost:8443/test/test.xhtml?param=foo
在我的浏览器中。正如我所料,日志声明视图参数设置为“foo”。现在我正在挣扎的是,当我第一次按下按钮时,日志再次声明param被设置为“foo”,证明setter再次被调用。我不明白为什么ajax请求会再次设置view参数。我还感到困惑的是,任何后续的按钮单击都不会再次调用视图参数的setter,特别是当第一次和所有后续调用看起来完全相同时

因此,我的问题是:

  • 为什么视图参数的setter在第一次ajax调用时被调用,而在随后的调用中没有被调用
  • 有没有办法防止这种行为
我正在Wildfly 19上运行这个例子,它使用Mojarra 2.3.9.SP06,如果这有帮助的话

编辑1:为了更清楚,为什么这个问题不同于。另一个问题是为什么视图参数在第一次ajax调用后丢失,以及如何始终发送它们。问题正好相反:为什么视图参数还是第一次发送?如何防止

另一个问题的答案是可以调用
FacesContext.getCurrentInstance().isPostback()
。我知道这一点。当然,它在检测ajax调用的意义上起作用,并使我能够在这种情况下不重置视图参数,但它并不会阻止视图参数的setter首先被调用。这是我理想中想要实现的目标。我还希望自己至少能够理解为什么在第一次ajax调用中对视图参数的处理会有所不同。我想在概念上我还没有理解

编辑2:我在下提交了一份错误报告。

快速解决方案 解决此问题的最佳方法是使用with
includeViewParams
设置为
true
setParam
在每个ajax请求上调用;只有在ajax请求中参数可以更改时才使用)

@Kukeltje已经说过(这与重写
UIViewParameter
的作用相同),因此
setParam
方法在开始时只调用一次


解释 基本上是在第一个ajax请求的初始请求期间保存的参数值。在第一个ajax请求之后,值最终丢失

理解这一点的最佳方法可能是逐阶段分析(查看以了解这些方法的作用也很有帮助):


初始请求 恢复视图阶段:没有任何特定内容

应用请求值阶段:
decode
已调用且
rawValue
已使用当前参数值设置

流程验证阶段:没有特定的内容

更新模型值阶段:调用
setParam
,然后调用
UIInput.resetValues()
,将
submittedValue
设置为null

调用应用程序阶段:没有特定的内容

呈现响应阶段:
setSubmittedValue
(为空)通过
rawValue
调用(已设置rawValue;请参阅应用请求值阶段)

第一个Ajax 还原视图阶段:rawValue重新初始化为
null

应用请求值阶段:
decode
已调用且
rawValue
已使用当前参数值设置(参数值为
null

流程验证阶段:没有特定的内容

更新模型值阶段:
setParam
使用
submittedValue
调用,该值设置为
null
,但在渲染响应阶段再次设置<再次调用code>UIInput.resetValues(),并将
submittedValue
设置为
null

调用应用程序阶段:没有特定的内容

渲染响应阶段:
setSubmittedValue
再次被调用并设置为
rawValue
,即
null

下面的每个ajax请求
submittedValue
rawValue
null
因此所有恢复参数值的可能性都被破坏<代码>设置参数不再被调用


所有解决方案
  • 重写
    encodeAll
    方法不再执行任何操作,因此
    UIInput.resetValues()
    将永远重置值(请参阅)
  • 使用
    o:viewParam
    (没有
    rawValue
    变量)
  • 使用
    o:form
当参数在ajax请求期间不变时,前两个解决方案是最好的


重写UIViewParameter 要覆盖
UIViewParameter
,请创建一个扩展
UIViewParameter
的类,并将其添加到
faces config.xml

<component>
    <component-type>javax.faces.ViewParameter</component-type>
    <component-class>com.example.CustomUIViewParameter</component-class>
</component>

javax.faces.ViewParameter
com.example.CustomUIViewParameter

你在概念上没有误解。我也不明白

我目前仍在研究为什么在第一次调用setter,并且只在第一次ajax回调中调用setter。我早就料到了
<o:viewParam id="param" name="param" value="#{testController.param}"/>
<context-param>
    <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
    <param-value>true</param-value>
</context-param>
@Override
public String getSubmittedValue() {
    return submittedValue;
}

@Override
public void setSubmittedValue(Object submittedValue) {
    this.submittedValue = (String) submittedValue; // Don't delegate to statehelper to keep it stateless.
}
@Override
public Object getSubmittedValue() {
    return getStateHelper().get(PropertyKeys.submittedValue);
}

/**
 * PENDING (docs)  Interesting that submitted value isn't saved by the parent
 * @param submittedValue The new submitted value
 */
@Override
public void setSubmittedValue(Object submittedValue) {
    getStateHelper().put(PropertyKeys.submittedValue, submittedValue);
}