有趣的案例。对于每个人,以下最小代码重现了这一点:
小面:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<f:metadata>
<f:viewParam id="id" name="id" value="#{viewParamBean.id}"/>
</f:metadata>
<h:body>
<h:messages />
#{viewParamBean.id} <br/>
<h:form>
<h:inputText value="#{viewParamBean.text}" >
<f:validateLength minimum="2"/>
</h:inputText>
<h:commandButton value="test" action="#{viewParamBean.actionMethod}"/>
</h:form>
</h:body>
</html>
豆:
@ManagedBean
@RequestScoped
public class ViewParamBean {
private long id;
private String text;
public void actionMethod() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
如果您用它调用 Facelet,viewparam.xhtml?id=12
它将显示在12
屏幕上。如果您随后输入了一些有效的内容,例如aaaaa
,id 将从 URL 中消失,但会继续显示在屏幕上(由于 ui 组件的有状态特性)。
但是...正如 OP 所提到的,一旦发生任何验证器错误(例如输入a
),该 ID 将永久丢失。之后输入有效输入不会将其恢复。这几乎看起来像一个错误,但我尝试了 Mojarra 2.1 和 Myfaces 2.1 并且两者都有相同的行为。
更新:
经过一番检查,问题似乎出在 `UIViewParameter' (Mojarra) 的这种方法中:
public void encodeAll(FacesContext context) throws IOException {
if (context == null) {
throw new NullPointerException();
}
// if there is a value expression, update view parameter w/ latest value after render
// QUESTION is it okay that a null string value may be suppressing the view parameter value?
// ANSWER: I'm not sure.
setSubmittedValue(getStringValue(context));
}
然后更具体地说是这种方法:
public String getStringValue(FacesContext context) {
String result = null;
if (hasValueExpression()) {
result = getStringValueFromModel(context);
} else {
result = (null != rawValue) ? rawValue : (String) getValue();
}
return result;
}
因为hasValueExpression()
是 true,它会尝试从模型(支持 bean)中获取值。但是由于这个 bean 是请求范围的,它不会对该请求有任何值,因为验证刚刚失败,因此没有设置任何值。实际上,有状态的值UIViewParameter
会被支持 bean 返回的任何默认值覆盖(通常为 null,但它当然取决于您的 bean)。
一种解决方法是制作您的 bean @ViewScoped
,这通常是一个更好的范围(我假设您使用该参数从服务中获取用户,并且可能没有必要在每次回发时一遍又一遍地这样做)。
另一种选择是创建自己的版本,如果验证失败(基本上所有其他组件都这样做)UIViewParameter
,则不会尝试从模型中获取值。UIInput