【问题标题】:How can I skip bean validation if all fields for the entity are empty?如果实体的所有字段都为空,如何跳过 bean 验证?
【发布时间】:2013-07-05 15:18:32
【问题描述】:

我有一个这样的地址实体:

@Entity
public class Address implements java.io.Serializable {
    @Id @GeneratedValue(strategy = IDENTITY)
    private Long id;

    @Size(max = 100)
    private String street;

    @Size(max = 15)
    private String nr;

    @Field
    @Size(min = 1, max = 20) @NotBlank
    private String city;
}

这是其他几个实体的一部分。对于这样一个实体,地址是可选的。 我有一个视图,我们的用户可以通过几个表单输入来编辑整个实体,包括几个地址字段。

为了能够编辑地址,我用空地址实体初始化父实体。

现在的问题是:当所有地址字段为空时,我不想在实体上保留 Address。为此,当(且仅当)Address 的所有字段为空时,我需要跳过对实体的验证。我该如何以最优雅的方式做到这一点?

我目前正在做的是使用<o:validateBean disabled="true" /> 为提交按钮完全跳过bean 验证,如果它是空的,则将地址设置为null。但这听起来像是一个彻头彻尾的黑客攻击,因为它在 all 情况下禁用了 all 验证。我怎样才能做得更好?

【问题讨论】:

    标签: jsf-2 bean-validation omnifaces


    【解决方案1】:

    您可以只在<f:validateBean>(和<o:validateBean>)的disabled 属性中使用EL。您可以使用 EL 检查是否已填写任何这些字段。您可以使用binding 属性来引用EL 中的组件。您可以通过检查与组件的客户端 ID 关联的请求参数的值来检查字段是否已填充。

    然后,要在 #{addressIsEmpty} 评估 true 时禁用这些字段的 bean 验证,使用 <f:validateBean> 而不是 <o:validateBean> 更容易,因为前者可用于包装多个输入组件。

    所以,总而言之,应该这样做:

    <c:set var="addressIsEmpty" value="#{empty param[street.clientId] and empty param[nr.clientId] and empty param[city.clientId]}" />
    
    <f:validateBean disabled="#{addressIsEmpty}">
        <h:inputText binding="#{street}" value="#{bean.address.street}" />
        <h:inputText binding="#{nr}" value="#{bean.address.nr}" />
        <h:inputText binding="#{city}" value="#{bean.address.city}" />
    </f:validateBean>
    

    &lt;o:validateBean&gt; 只有在您打算基于每个输入或每个命令进行控制时才更易于使用。

    【讨论】:

    • 嗯,虽然检查 param 值工作得很好,但我不得不使用 id 的字符串值(我控制命名容器和输入的 ids),使用 @987654333 @ 在尝试评估 EL 时给了我一个 NullPointerException。这可能是因为这些值位于有条件呈现的弹出窗口中吗?
    • 我在引用任何绑定时得到Parameter key is null。虽然这仅适用于&lt;c:set&gt;&lt;f:validateBean&gt;,但在&lt;h:outputText/&gt; 中输出它就可以了。听起来像是视图构建与渲染时间的问题?
    【解决方案2】:

    多个字段的交叉验证可能是一个棘手的问题。但是在这种情况下,首先困扰您的不是验证本身,而是在您持久化实体之前在您的 bean 中的某些条件下使某些实例无效的可能性。

    最直接的方法是将与Address 实体关联的所有字段标记为required="false" 在您的视图中不关心正在填写的字段(或者只是省略它,因为它是默认值)并执行所有检查,并在调用 EJB 服务之前修改操作方法中的占位符。像这样:

    public String save() {
        //do some checks
        if((entity.getAddress().getStreet() == null) && ...) {
            //assign address to null
            entity.setAddress(null);
        }
        entityService.persist(entity);
        return "success";
    }
    

    【讨论】:

    • 问题在于 JSF 默认会进行 Bean 验证,即使字段是 required=false(它们在我的代码中)。未能通过验证,即使完全合理,也意味着我的 save 永远不会被调用。
    • 是的,这很好!像往常一样,BalusC 的回答让我们再次走上正轨。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多