关于jsf 2:如果实体的所有字段均为空,如何跳过bean验证?

How can I skip bean validation if all fields for the entity are empty?

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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,则将其设置为null。但这听起来像是一个骇客,因为它在所有情况下都会禁用所有验证。我该如何做得更好?


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

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

因此,应该全部这样做:

1
2
3
4
5
6
7
<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>

<o:validateBean>仅在打算基于每个输入或每个命令进行控制时更易于使用。


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

最直接的方法是在您的视图中将与Address实体相关联的所有字段标记为required="false",而不关心字段是否被填充(或者默认情况下将其忽略)并进行所有检查,然后在调用EJB服务之前对操作方法中的占位符进行修改。像这样:

1
2
3
4
5
6
7
8
9
public String save() {
    //do some checks
    if((entity.getAddress().getStreet() == null) && ...) {
        //assign address to null
        entity.setAddress(null);
    }
    entityService.persist(entity);
    return"success";
}