我最近一直在开发一些JSF应用程序,并对web组件API中的不一致性感到不安。
我注意到,在服务器端代码中,当对JSF组件对象调用.getValue()或.getSubmittedValue()时,会出现极不可预测的行为。有时,当我在下拉列表框中调用.getValue()时,我注意到我会得到选择值之前的值(因此是上次刷新页面时的值),其中.getSubmittedValue()会得到正确的值,例如:
UIInput name = new UIInput(); // This is the control I have in a bean.
public void submit(ActionEvent ae)
{
someMethod(name.getValue().toString()); // Retrieves the "old" value
someMethod(name.getSubmittedValue().toString()); // Retrieves the correct value
}
此外,我注意到对表单字段调用.getSubmittedValue()有时会导致空指针异常,因为该值尚未在组件对象中实例化,在这种情况下,当我在这种情况中调用.getValue()时,我会得到正确的值,例如:
HtmlInputText name = new HtmlInputText(); // This is the control I have in a bean.
public void submit(ActionEvent ae)
{
someMethod(name.getValue().toString()); // Retrieves the correct value
someMethod(name.getSubmittedValue().toString()); // Throws NullPointerException
}
这只是JSF框架的一个"怪癖",还是我只是完全错误地使用了API??如能深入了解这两种方法,我们将不胜感激。干杯
由于这是谷歌搜索getValue与getSubmittedValue的第一个结果,我只想补充一点,它们之间的差异在验证中至关重要(即,在编写自定义验证器时)
为getSubmittedValue()引用API文档:
仅在解码之间为非空并验证阶段,或者组件的验证尚未成功。一旦转换和验证已成功(转换后的)值存储在此的本地"值"属性组件,并且提交的值为重置为空。
来源:http://myfaces.apache.org/core11/myfaces-api/apidocs/javax/faces/component/UIInput.html#getSubmittedValue()
这意味着,如果您试图访问的绑定已经进行了验证/转换,那么您应该调用getValue(),否则您将不得不调用getSubmittedValue()并自己进行解析。它们出现的顺序似乎是由它们在UI中的显示顺序决定的,但我认为这并不能保证。即使是这样,您也不应该指望更改UI中的字段不会破坏代码。
您可以通过查看isLocalValueSet()返回的内容来检测验证/转换是否已完成。如果返回true,则表示赋值/转换已经完成,因此应该调用getValue()。否则,您需要调用getSubmittedValue(),这将为您提供用户输入的原始输入,您可能希望将其解析为更有意义的内容。
例如,当调用getValue()时,日历对象将返回Date对象,而当调用getSubmittedValue()则返回String对象。由您的转换器将字符串解析为Date,以便对其进行验证。
如果JSF规范有一个可以为我们做到这一点的方法,那就太好了,但AFAIK没有。如果某些日期需要在其他日期之前,并且某些日期仅在特定情况下才需要,则需要编写几个验证器来处理此问题。因此,它很容易成为一个问题。这类似于不能对空白字段进行任何类型的验证,这意味着不能有条件地要求该字段。如果验证是在所有字段上运行的,甚至是空白字段,那么可以编写一个自定义验证器来抛出异常(如果应该需要而不是)。JSF有一些问题,这只是一种痛苦;除非/直到它们被修复,否则我们只能处理它们。
在最初的帖子中谈到这个问题的细节:这里的区别在于你在生命周期中所处的位置。submit
方法看起来像是按钮的动作监听器,它将按钮置于生命周期的末尾;操作和操作侦听器是在"调用应用程序"阶段触发的,该阶段在呈现响应之前,但在验证之后。如果你要用JSF编程,你应该学习并理解生命周期。花时间是值得的。
引用EditableValueHolder.getSubmittedValue:上的文档
返回的submittedValue值此组件。此方法应只能由encodeBegin()使用和/或encodeEnd()方法组件,或其对应的渲染器。
通常,您甚至不会调用getValue。相反,组件的值属性应该绑定到您的模型(可能是bean)。您的业务逻辑将与模型交互,而不是与组件交互。
如果提交的值没有被设置为值,那么我猜某些验证失败了。唯一的问题是你的活动被解雇了。这里的问题有两种猜测:
- 您对组件对象有一个过时的引用
- 您已经在UICommand上设置了immediate属性,这意味着在组件处于不适当状态的阶段触发事件
根据所提供的信息无法确定。
我在基于JSF的xpages上工作,所以…它可能是一样的。。。
无论如何,getSubmittedValue();总是返回您在firebug/chrome develepers网络选项卡中看到的内容。这是发送数据包中的值。我在标题选项卡的表单数据部分显示了它(chrome),名称为$$xspsubmitvalue。
另一方面,getValue()是特定于组件的<--这里不是100%确定。
TL;DR答案:
UIViewRoot viewRoot = context.getViewRoot();
UIInput input = (UIInput)viewRoot.findComponent(":form:inputID");
String inputValueString;
if (input.isLocalValueSet()) {
inputValueString = (String)input.getValue(); //validated and converted already
} else {
inputValueString = (String)input.getSubmittedValue(); //raw input
}
或者至少其他答案是这么说的…
只需使用.getSubmittedValue()
并处理必须转换原始输入的后果(如果需要,如果原始输入需要转换)。.getValue()
在这方面被破坏了,即使使用了上面的代码。如果您使用它,它会延迟提交的值,这是不可接受的。