[英]JSF 2 - Bean Validation: validation failed -> empty values are replaced with last valid values from managed bean
我不明白 JSF2 在验证期间的行为。 希望有人可以帮助我。
我有一个表单,在(ajax)提交后验证字段 - 好的
如果验证失败,则会显示一条错误消息 - 好的
对于我的示例,当我输入有效的生日并且字段名称为空时,提交后会显示名称的错误消息。
现在,当我输入有效姓名并从生日字段中删除输入时,会显示生日错误消息(没关系)但现在旧的“有效”生日也在输入字段中!?!
我怎样才能避免这种行为? 当我提交一个空字段时,我想看到一条错误消息和一个空字段...
这是我的示例代码:
我使用包含 EntityBean ( Contact ) 的 ManagedBean ( TestBean )。 联系人包含每个注释的验证。
public class Contact implements Serializable {
@NotNull
@Temporal(TemporalType.DATE)
private Date birthday;
@NotNull
@Size(min=3, max=15)
private String name;
//...
}
我的ManagedBean :
@ManagedBean
@ViewScoped
public class TestBean implements Serializable {
private Contact contact;
@PostConstruct
void init() {
System.out.println("init...");
contact = new Contact();
}
public void newContact(ActionEvent ae) {
System.out.println("newContact...");
contact = new Contact();
}
public void save() {
System.out.println("save...");
//TODO do something with contact...
}
public Contact getContact() { return contact; }
public void setContact(Contact contact) {this.contact = contact;}
}
这里是我的 JSF 页面:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core" >
<h:body>
<h:form>
<h:panelGrid columns="3">
<h:outputText value="Birthday: " />
<h:inputText id="birthday" value="#{testBean.contact.birthday}">
<f:convertDateTime/>
</h:inputText>
<h:message for="birthday" />
<h:outputText value="Name: " />
<h:inputText id="name" value="#{testBean.contact.name}"/>
<h:message for="name" />
</h:panelGrid>
<h:commandButton value="submit" action="#{testBean.save}">
<f:ajax execute="@form" render="@form"/>
</h:commandButton>
<h:commandButton value="newContact" actionListener="#{testBean.newContact}"
immediate="true">
<f:ajax render="@form"/>
</h:commandButton>
</h:form>
</h:body>
</html>
最后一个来自 web.xml 的片段
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name>
<param-value>true</param-value>
</context-param>
谢谢你的一些提示
您的特定问题是由
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
以及HtmlBasicRenderer#getCurrentValue()
的一个错误(至少是一个疏忽):
if (component instanceof UIInput) {
Object submittedValue = ((UIInput) component).getSubmittedValue();
if (submittedValue != null) {
// value may not be a String...
return submittedValue.toString();
}
}
String currentValue = null;
Object currentObj = getValue(component);
if (currentObj != null) {
currentValue = getFormattedValue(context, component, currentObj);
}
return currentValue;
通常,当UIInput
组件成功转换和验证时,提交的值设置为null
。 当 JSF 将要重新显示该值时,它首先检查提交的值是否为null
然后再继续重新显示模型值。 但是,对于这个上下文参数,当它无效时它是null
而不是空字符串,因此当您删除必填字段的初始值时,它将始终重新显示原始模型值。
要测试它,请将该上下文参数值设置为false
或将其完全删除。 你会看到它按预期工作。 但是,它会带来一个缺点,即您的模型值将在空但非必需的字段上被空字符串弄乱,并且您将失去使用 JSR 303 bean 验证的@NotNull
注释的优势。
要解决此问题,您必须按如下方式更改HtmlBasicRenderer#getCurrentValue()
的第一部分:
if (component instanceof UIInput && !((UIInput) component).isValid()) {
Object submittedValue = ((UIInput) component).getSubmittedValue();
if (submittedValue != null) {
// value may not be a String...
return submittedValue.toString();
} else {
return null;
}
}
我已经将其作为issue 2266报告给了 Mojarra 人员。
有一个类似的问题,当字段被清空并且另一个组件验证失败时,从支持 bean 加载的值将被重置。 我必须对 BalusC 的代码稍加添加才能使其工作。
protected String getCurrentValue(FacesContext context,
UIComponent component) {
if (component instanceof UIInput && !((UIInput) component).isValid()) {
Object submittedValue = ((UIInput) component).getSubmittedValue();
if (submittedValue != null) {
// value may not be a String...
return submittedValue.toString();
} else {
return null;
}
}
String currentValue = null;
Object currentObj;
if ( component instanceof UIInput && ((UIInput)component).isLocalValueSet() )
{
currentObj = ((UIInput)component).getLocalValue();
}
else {
currentObj = getValue(component);
}
if (currentObj != null) {
currentValue = getFormattedValue(context, component, currentObj);
}
return currentValue;
}
我认为在正常使用期间人们不会输入有效日期,提交,然后在再次提交之前删除日期。 我意识到您在测试期间发现了这一点,但可能人们只是想成功填写表单而不是删除他们已经输入的内容,在这种情况下,保留最后一个有效值是最好的功能。
如果你坚持......似乎setter方法“生日”从未被调用,因为该值无效,然后当页面重新显示时,“生日”的当前值被显示(当前值是有效值)以前保存)。 也许您可以编写一个自定义验证器来设置值然后验证该值,但这并没有多大意义。 对于用户输入诸如“昨天”之类的文本字符串而不是有效日期的情况,您仍然必须首先验证该值,然后您必须根据该无效值将日期设置为某个值,然后您将有将消息添加到 FacesContext。 因此,代码必须执行以下操作。
1) 验证日期值
2) 如果它无效,则将该字段设置为某个有意义的值并向 FacesContext 添加错误消息。
3) 如果它有效,则使用它。
这是可行的,但很奇怪,因为即使传入的值无效,您也在更改字段的值...
Aaron 已经描述了这种行为。
通过单击“newContact”按钮,我所描述的问题也存在。 如果第一次提交无效(输入生日,名称字段为空),则会显示错误消息。 好的。
之后“newContact”按钮不会刷新(清除)视图。 尽管模型已重置(contact = new Contact())。
我在这里找到了一些提示: http ://wiki.apache.org/myfaces/ClearInputComponents
这是我的解决方案:
public void newContact(ActionEvent ae) {
contact = new Contact();
contact.setBirthday(new Date()); //for testing only
resetForm(ae.getComponent());
}
private void resetForm(UIComponent uiComponent) {
//get form component
UIComponent parentComponent = uiComponent.getParent();
if (uiComponent instanceof UIForm)
resetFields(uiComponent);
else if (parentComponent != null)
resetForm(parentComponent);
else
resetFields(uiComponent);
}
private void resetFields(UIComponent baseComponent) {
for (UIComponent c : baseComponent.getChildren()) {
if (c.getChildCount() > 0)
resetFields(c);
if (c instanceof UIInput)
((UIInput) c).resetValue();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.