JSF 不支持跨字段验证,有解决方法吗?

Posted

技术标签:

【中文标题】JSF 不支持跨字段验证,有解决方法吗?【英文标题】:JSF doesn't support cross-field validation, is there a workaround? 【发布时间】:2011-09-11 01:36:24 【问题描述】:

JSF 2.0 只允许您验证一个字段的输入,例如检查它是否为特定长度。它不允许您使用“输入城市和州,或仅输入邮政编码”的表格。

你是怎么解决这个问题的?我只对涉及 JSF 验证阶段的答案感兴趣。我对将验证逻辑放入托管 Bean 不感兴趣。

【问题讨论】:

自从我发布了这个问题......已经出现了一些替代方案。一、Omnifaces:code.google.com/p/omnifaces 二:JSF2.2 发布后会支持这个 【参考方案1】:

到目前为止,我见过和使用的最简单的自定义方法是创建一个带有 <f:validator><h:inputHidden> 字段,其中您将所有涉及的组件引用为 <f:attribute>。如果在待验证组件之前声明它,则可以通过UIInput#getSubmittedValue()获取验证器内部提交的值。

例如

<h:form>
    <h:inputHidden id="foo" value="true">
        <f:validator validatorId="fooValidator" />
        <f:attribute name="input1" value="#input1" />
        <f:attribute name="input2" value="#input2" />
        <f:attribute name="input3" value="#input3" />
    </h:inputHidden>
    <h:inputText binding="#input1" value="#bean.input1" />
    <h:inputText binding="#input2" value="#bean.input2" />
    <h:inputText binding="#input3" value="#bean.input3" />
    <h:commandButton value="submit" action="#bean.submit" />
    <h:message for="foo" />
</h:form>

(请注意隐藏输入上的value="true";实际值实际上并不重要,但请记住,验证器不一定会在它为空或为空时被触发,具体取决于 JSF版本和配置)

@FacesValidator(value="fooValidator")
public class FooValidator implements Validator 

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException 
        UIInput input1 = (UIInput) component.getAttributes().get("input1");
        UIInput input2 = (UIInput) component.getAttributes().get("input2");
        UIInput input3 = (UIInput) component.getAttributes().get("input3");
        // ...
        
        Object value1 = input1.getSubmittedValue();
        Object value2 = input2.getSubmittedValue();
        Object value3 = input3.getSubmittedValue();
        // ...
    


如果在待验证组件之后声明&lt;h:inputHidden&gt;,那么所涉及组件的值已经被转换和验证,你应该通过UIInput#getValue()或者@改为 987654323@(如果 UIInput 不是 isValid())。

另见:

Validator for multiple fields (JSF 1.2 targeted)

或者,您可以为此使用 3rd 方标签/组件。例如RichFaces 有一个&lt;rich:graphValidator&gt; 标签,Seam3 有一个&lt;s:validateForm&gt;,OmniFaces 有几个标准的&lt;o:validateXxx&gt; 组件,它们都展示了here。 OmniFaces 使用基于组件的方法,工作在UIComponent#processValidators() 中完成。它还允许customizing它以这样的方式实现上述目标:

<h:form>
    <o:validateMultiple id="foo" components="input1 input2 input3" validator="#fooValidator" />
    <h:inputText id="input1" value="#bean.input1" />
    <h:inputText id="input2" value="#bean.input2" />
    <h:inputText id="input3" value="#bean.input3" />
    <h:commandButton value="submit" action="#bean.submit" />
    <h:message for="foo" />
</h:form>

@ManagedBean
@RequestScoped
public class FooValidator implements MultiFieldValidator 

    @Override
    public boolean validateValues(FacesContext context, List<UIInput> components, List<Object> values) 
        // ...
    

唯一的区别是它返回一个boolean,并且消息应该在&lt;o:validateMultiple&gt;中指定为message属性。

【讨论】:

也可以使用 RichFaces graphValidator richfaces-showcase.appspot.com/richfaces/… @Joshua: 或 JSR303 bean 验证。 @BalusC:是的。或者 SeamFaces 表单验证器 docs.jboss.org/seam/3/faces/latest/reference/en-US/html/… 目前这是我最喜欢的。 @BalusC 我尝试了这种技术,当我从隐藏输入的validate() 方法中抛出ValidatorException 时,我没有在屏幕中看到错误消息。如果我将其设为常规输入,我会在屏幕上看到错误消息。如何将错误消息与导致验证失败的组件一起应用? @Geek:默认情况下,抛出的ValidatorException 中的消息将与触发验证的组件相关联,在您的情况下,该组件是隐藏的输入。只需添加一个&lt;h:message for="hiddenId"&gt; 即可使其显示在其中。或者手动将消息添加到所需客户端 ID 的上下文中,并将组件和上下文手动标记为无效。另见例如***.com/questions/14012225/… 和 OmniFaces 验证器组件的源代码与此处的回答基本完全相同。【参考方案2】:

这里没有提到Apache ExtVal

其中有一些交叉验证(以及其他可能有用的验证):

https://cwiki.apache.org/confluence/display/EXTVAL/Property+Validation+Usage#PropertyValidationUsage-CrossValidation

【讨论】:

以上是关于JSF 不支持跨字段验证,有解决方法吗?的主要内容,如果未能解决你的问题,请参考以下文章

必填字段的 JSF 验证

前端设置请求头可以解决跨域问题吗

跨域解决方法

怎么解决跨域问题

解决Ajax不能跨域的方法

ThInkPHP验证码不显示,解决方法汇总