现在,Bean Validation 已正式成为 Java EE 6 的一部分,并且 Java EE 6 也正式投票通过 YES,让我们看看 Bean Validation 是如何与其他生态系统集成的。

什么是 Bean Validation

它的目标是让应用程序开发人员通过注释他们的模型一次性地声明数据约束,并确保这些约束以一致的方式由应用程序的不同层进行验证。如果没有 Bean Validation,人们必须在他们的首选表示框架中编写验证规则,然后在业务层,然后在持久化层,在一定程度上在数据库模式中,并保持所有这些同步。

下面是这种集中式约束声明的样子

class User {
  @NotEmpty @Size(max=100)
  String getLogin() { ... }

  @NotEmpty @Size(max=100)
  String getFirstname() { ... }
  
  @Email @Size(max=250)
  String getEmail() { ... }
  ...
}

还有很多其他功能,比如约束组合、分组,但让我们集中关注 Bean Validation 如何与 EE 6 栈集成。

那么,我需要做什么才能使其在 Java EE 6 中工作

简短的回答是,什么都不用做。甚至不需要 XML 配置技巧。

只需在您的领域模型上添加约束,平台就会为您做剩下的工作。

JSF 以及如何将约束违规暴露给用户

在 JSF 中,您将表单输入绑定到领域模型的属性。JSF 2 和 Bean Validation 聪明地确定您绑定的是哪个属性,并执行与该属性关联的约束。

<h:form id="register">
    <div style="color: red">
        <h:messages id="messages" globalOnly="true"/>
    </div>

    <div>
        Login:
        <h:inputText id="login" value="#{identifier.user.login}"/>
        <h:message style="color: red" for="login"/>
        <br/>
        Password:
        <h:inputSecret id="password" value="#{identifier.user.password}"/>
        <h:message style="color: red" for="password"/>
        <br/>
        Firstname:
        <h:inputText id="firstname" value="#{identifier.user.firstname}"/>
        <h:message style="color: red" for="firstname"/>
        <br/>
        Email:
        <h:inputText id="email" value="#{identifier.user.email}"/>
        <h:message style="color: red" for="email"/>
        <br/>

        <h:commandButton id="Login" value="Login" action="#{identifier.register}"/>
        <br/>
        <h:button id="cancel" value="Cancel" outcome="/home.xhtml"/>
    </div>
</h:form>

例如,如果电子邮件格式不正确并且名字为空,Bean Validation 将将约束违规返回给 JSF 2,JSF 2 将将其以本地化错误消息的形式暴露给用户。默认情况下,它会自动工作,您甚至不需要考虑它。

对于更高级的使用场景,例如为单个或多个字段禁用约束验证,或使用特定组或组集而不是默认组,您可以使用<f:validateBean/>标签(检查以下示例中的第8行和第20行)。

<h:form id="register">
    <div style="color: red">
        <h:messages id="messages" globalOnly="true"/>
    </div>

    <div>
        <!-- ***** use a specific group ***** -->
        <f:validateBean validationGroups="${identifier.validationGroups}">
            Login:
            <h:inputText id="login" value="#{identifier.user.login}"/>
            <h:message style="color: red" for="login"/>
            <br/>
            Password:
            <h:inputSecret id="password" value="#{identifier.user.password}"/>
            <h:message style="color: red" for="password"/>
            <br/>
            Firstname:
            <!-- ***** disable validation for firstname ***** -->
            <h:inputText id="firstname" value="#{identifier.user.firstname}">
                <f:validateBean disabled="true"/>
            </h:inputText>
            <h:message style="color: red" for="firstname"/>
            <br/>
            Email:
            <h:inputText id="email" value="#{identifier.user.email}"/>
            <h:message style="color: red" for="email"/>
            <br/>

            <h:commandButton id="Login" value="Login" action="#{identifier.register}"/>
            <br/>
            <h:button id="cancel" value="Cancel" outcome="/home.xhtml"/>
        </f:validateBean>
    </div>
</h:form>

在未来,我们希望与RichFaces合作,以便在客户端的JSF组件上验证对象模型上声明的约束。这是我们之前已经原型化过的事情,Pete、Dan和我最初向JSF 2专家小组提出,但我们必须降低我们的雄心壮志 :) 我们在这个领域期待一些创新。

但您的所有数据并不都来自表示层。

JPA 2:最后的防线

同样,默认情况下,您的JPA 2提供程序将在您即将持久化或更新的实体上运行Bean Validation。这样,您可以保证不会将无效数据放入您的数据库中,从而提高整体数据质量。哦,这些约束与您在JSF 2.0中要验证的约束相同。

您可以使用validation-mode元素在persistence.xml中禁用JPA 2中的验证,或者使用javax.persistence.validation.mode属性并将它们设置为none。更有趣的是,您可以选择在实体持久化、更新甚至删除操作时验证哪个组。默认情况下,Default组在您持久化或更新实体时进行验证。使用这些属性中的任何一个来调整。

<property name="javax.persistence.validation.group.pre-persist" 
        value"javax.validation.groups.Default, com.acme.model.Structural"/>
<property name="javax.persistence.validation.group.pre-update" 
        value"javax.validation.groups.Default, com.acme.model.Structural"/>

<property name="javax.persistence.validation.group.pre-delete" 
        value"com.acme.model.SafeDestruct"/>

Hibernate Core和Hibernate Validator在这方面做得更多,并将约束传播到数据库模式中(前提是您允许Hibernate Core为您生成或更新模式)。只需将hibernate.hbm2ddl.auto属性设置为create, updatecreate-drop.

我的服务层怎么办?

您可以在Java EE 6中的任何可注入的POJO中注入一个ValidatorValidatorFactory实例。

class SalesService {
  @Inject Validator validator;
  @Inject @Current User user;

  public boolean canBuyInOneClick() {
    return validator.validate(user, BuyInOneClick.class).size() == 0;
  }

我在哪里可以尝试它?

所有这些现在都可在刚刚发布的JBoss AS 6 M1中找到。享受吧!


返回顶部