JSF 2 – Beanvalidation:validation失败 – >空值被替换为来自托管bean的最后一个有效值

我不理解在valration期间JSF2的行为。 希望可以有人帮帮我。

我有一个表单,其中字段在(ajax)提交后validation – 确定
如果validation失败,则会显示错误消息 – 确定

对于我输入有效生日并且字段名称为空的示例,提交后会显示名称的错误消息。
现在,当我输入有效名称并从生日字段中删除输入时,将显示生日错误消息 (没关系),但现在旧的“有效” 生日也会出现在输入字段中!?!

我怎样才能避免这种行为? 当我提交一个空字段时,我想看到一个错误消息和一个空字段……

这是我的示例代码:

我使用包含EntityBean( Contact )的ManagedBean( TestBean )。 联系人包含每个年度的validation。

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页面:

                       

最后一个来自web.xml的片段

  javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL true   javax.faces.VALIDATE_EMPTY_FIELDS true  

谢谢你的一些提示

你的特殊问题是由

  javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL true  

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; 

通常,在成功转换和validationUIInput组件时,提交的值将设置为null 。 当JSF即将重新显示该值时,它首先检查提交的值是否为null然后再继续重新显示模型值。 但是,使用此上下文参数时,如果它无效,则它为null而不是空字符串,因此当您删除必填字段的初始值时,它将始终重新显示原始模型值。

要测试它,请将该上下文参数值设置为false或将其完全删除。 你会发现它按预期工作。 但是,它会带来一个缺点,即模型值将在空的但非必需的字段上用空字符串混乱,并且您将失去使用JSR 303 beanvalidation的@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; } } 

我已经向Mojarra家伙报告了问题2262 。

我想在正常使用期间,人们不会输入有效日期,提交,然后在再次提交之前删除日期。 我意识到你在测试期间发现了这一点,但可能人们只是试图成功填写表单而不是删除他们已输入的内容,在这种情况下,保留最后一个有效值可能是最好的function。

如果你坚持……似乎从未调用setter方法“birthday”,因为该值无效,然后当页面被重新显示时,显示当前的“birthday”值(当前值是有效值,即以前保存过)。 也许你可以编写一个设置值的自定义validation器,然后THENvalidation值,但这实际上没有多大意义。 当用户输入“昨天”而不是有效日期等文本字符串时,您仍然需要首先validation值,然后您必须根据该无效值将日期设置为某个值,然后您将拥有将消息添加到FacesContext。 因此代码必须执行以下操作。

1)validation日期值
2)如果它无效,则将该字段设置为某个有意义的值,并向FacesContext添加错误消息。
3)如果它有效则使用它。

这是可行的,但很奇怪,因为你改变了字段的值,即使传入的值无效……

亚伦已经描述了这种行为。

我已经描述的问题也存在于单击“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(); } } 

有一个类似的问题,当字段被清空而另一个组件validation失败时,从支持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; }