我有一个两个输入字段的表单,必须一起验证。我用这个BalusC tutorial作为起点。
要求是逻辑XOR:必须填写其中一个字段,但不能同时填充。
这适用于除此之外的所有情况:
1)填写第一个字段并让第二个字段
2)移动到下一页(值保存)
3)返回第一页,删除第一个字段并填写第二个字段。
然后我从验证器收到错误消息(“不要填写两个字段”),尽管我删除了第一个。
以下是代码:
<h:inputText id="bbvol" size="10" value="#{a6.behandlungsvolumen.wert}"
required="#{empty param['Laborwerte:pvol']}">
<f:convertNumber locale="de"/>
</h:inputText>
<h:inputText id="pvol" size="10" value="#{a6.plasmavolumen.wert}"
required="#{empty param['Laborwerte:bbvol']}">
<f:convertNumber locale="de"/>
<f:validator validatorId="volumeValidator" for="pvol"/>
<f:attribute name="bbv_value" value="Laborwerte:bbvol" />
</h:inputText>
VolumeValidator:
public class VolumeValidator implements Validator {
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
// Obtain the client ID of the first volume field from f:attribute.
String bbvolID = (String) component.getAttributes().get("bbv_value");
// Find the actual JSF component for the client ID.
UIInput bbvolInput = (UIInput) context.getViewRoot().findComponent(bbvolID);
// Get its value, the entered value of the first field.
Number bbvol = (Number) bbvolInput.getValue();
// Get the value of the second field
Number pvol = (Number) value;
// Check if only one of the fields is set
if (bbvol != null && pvol != null) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Do not fill both fields!", null));
}
}
}
调试此案例会显示该行
Number bbvol = (Number) bbvolInput.getValue();
仍然保留旧值,而不是新值。
我尝试使用getSubmittedValue()
代替getValue()
而使用。但是这种方法的javadoc说:
此方法仅应由 这个的decode()和validate()方法 组件,或其对应的 渲染器。
我不确定我是否可以使用此方法而不会在以后遇到问题。
所以我的问题是:
这个问题的原因是什么?
使用getSubmittedValue()
代替getValue()
是真正的解决方案吗?
答案 0 :(得分:3)
这不能解决问题。如果您测试getSubmittedValue()
,那么当您填写两个字段时,验证将(错误地)通过。在JSF中,输入组件按照它们在组件树中的显示顺序进行验证。成功转换/验证组件后,提交的值将设置为null
,并使用转换/验证的提交值设置该值。
然而,你的特殊情况让我感到震惊。我可以在Tomcat 7.0.11上使用Mojarra 2.0.4复制此问题。 getValue()
返回模型值而不是组件值。我不确定这是JSF2中的错误或新内容,但我确信它在JSF 1.x中已经有了这种方式。我相信这与新JSF2状态管理的变化有关。我必须先验证其中一个(并且可能还要重写多字段验证博客文章)。
作为另一种解决方案,您可以在两个组件之前添加<h:inputHidden>
,如下所示,以便您可以正确使用getSubmittedValue()
:
<h:form id="form">
<h:inputHidden value="true">
<f:validator validatorId="xorValidator" />
<f:attribute name="input1" value="form:input1" />
<f:attribute name="input2" value="form:input2" />
</h:inputHidden>
<h:inputText id="input1" value="#{bean.input1}" required="#{empty param['form:input2']}" />
<h:inputText id="input2" value="#{bean.input2}" required="#{empty param['form:input1']}" />
<h:commandButton value="submit" action="#{bean.submit}" />
<h:messages />
</h:form>
与
@FacesValidator(value="xorValidator")
public class XorValidator implements Validator {
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
UIInput input1 = (UIInput) context.getViewRoot().findComponent((String) component.getAttributes().get("input1"));
UIInput input2 = (UIInput) context.getViewRoot().findComponent((String) component.getAttributes().get("input2"));
Object value1 = input1.getSubmittedValue();
Object value2 = input2.getSubmittedValue();
// ...
}
}
答案 1 :(得分:1)
除了带有getValue()/ getSubmittedValue()的{feature | bug} - 2.x中的方法之外,您可以尝试使用RequiredIf-Annotation进行XOR验证:
@RequiredIf(validationErrorMsgKey = "requiredField", valueOf = { "pvol" } , is = RequiredIfType.empty )
private String bbvol;
@RequiredIf(validationErrorMsgKey = "requiredField", valueOf = { "bbvol" } , is = RequiredIfType.empty )
private String pvol;
这对我来说就像一个类似验证星座的魅力。