openxava / 文档 / 第十八章:使用 @EntityValidator 进行验证

课程:1. 入门教学 | 2. 基本域模型(上) | 3. 基本域模型(下) | 4. 优化用户界面 | 5. 敏捷开发 | 6. 映射式超类继承 | 7. 实体继承 | 8. 视图继承(View) | 9. Java 属性 | 10. 计算属性 | 11. 用在集合的 @DefaultValueCalculator | 12. @Calculation 和集合总计 | 13. 从外部文件的 @DefaultValueCalculator | 14. 手动更改 schema | 15. 多用户时默认值的计算 | 16. 同步持久属性和计算属性 | 17. 从数据库中的逻辑 | 18. 使用 @EntityValidator 进行验证 | 19. 验证替代方案 | 20. 删除时验证 | 21. 自定义 Bean Validation 注解 | 22. 在验证中调用 REST 服务 | 23. 注解中的属性 | 24. 改进标准行为 | 25. 行为与业务逻辑 | 26. 参照与集合 | A. Architecture & philosophy | B. Java Persistence API | C. Annotations | D. Automated testing

目录

第十八章:使用 @EntityValidator 进行验证
我们的验证
在 Order 中添加 delivered 属性
使用 @EntityValidator 进行验证
       总结
到目前为止,我们只使用 OpenXava 的 @Required 注解做了一些基本的验证。在本章,您将学到使用 @EntityValidator 注解进行验证。

我们的验证

我们将使用以下逻辑优化代码:如果订单尚未送达,则用户无法用它生成发票或分配给一个已存在的发票。也就是说,只有已送达的订单才能与发票相关联。

在 Order 中添加 delivered 属性

首先,在 Order 实体中添加一个新属性:已送达(delivered)
@Column(columnDefinition="BOOLEAN DEFAULT FALSE")
boolean delivered;
此外,必须将已送达(delivered)属性添加到视图中。请用以下代码修改 Order 的视图:
@View(extendsView="super.DEFAULT", 
    members=
        "estimatedDeliveryDays, delivered," + // 添加已送达
        "invoice { invoice }" 
)
...
public class Order extends CommercialDocument {
这个新属性允许用户在订单已送达时,改变订单的送达状态。试试新代码并将一些现有订单标记为已送达。

使用 @EntityValidator 进行验证

目前,用户可以在 Invoice 模块中将任何订单添加到任何发票,也能在 Order 模块将一个发票与任何订单相关联。我们将对此进行限制:只有已送达的订单可以添加到发票中。
实现此验证的第一个方案是使用 @EntityValidator。此注解允许您为实体指定您想要的验证逻辑。让我们在 Order 实体注解,如下:
@EntityValidator(
    value=com.yourcompany.invoicing.validators.DeliveredToBeInInvoiceValidator.class, // 具有验证逻辑的类
    properties= {
        //这些属性的值会在执行验证之前从 Order 实体中移到验证器
@PropertyValue(name="year"), @PropertyValue(name="number"), @PropertyValue(name="invoice"), @PropertyValue(name="delivered") } ) public class Order extends CommercialDocument {
每次新建或修改 Order 对象时,都会创建 DeliveredToBeInInvoiceValidator 对象。该对象会使用 Order 对象中的属性值,如 year、number、invoice 和 delivered。之后,验证器会执行 validate() 方法。现在我们将编写验证器的代码,首先创建 com.yourcompany.invoicing.validators 包,然后将下一个类放入其中:
package com.yourcompany.invoicing.validators; // 在 validators 包

import com.yourcompany.invoicing.model.*;
import org.openxava.util.*;
import org.openxava.validators.*;
import lombok.*;
 
@Getter @Setter 
public class DeliveredToBeInInvoiceValidator
    implements IValidator { // 必须实现 IValidator
 
    int year; // 要从 Order 注入的属性
    int number;
    boolean delivered;
    Invoice invoice;
 
    public void validate(Messages errors) // 验证的逻辑
        throws Exception
    {
        if (invoice == null) return;
        if (!delivered) {
            errors.add( // 在 errors 添加消息,验证将失败
                "order_must_be_delivered", // i18n 文件裡的 id
                year, number); // 消息的参数
         }
    }

}
验证的逻辑非常简单:如果已经有发票但该订单未标记为已送达时,我们会添加一条错误的消息,因此验证将失败。您应该在 invoicing/src/main/resources/i18n/invoicing-messages_zh.properties 文件中添加错误消息并将 invoicing-messages_en.properties 文件删除。如下所示:
# Messages for the Invoicing application
order_must_be_delivered=订单 {0}/{1} 必须已送达才能添加到发票中

//在这里,以上中文会以unicode(統一碼)显示 < 请勿复制这行
现在您可以尝试将订单添加到一个发票中,您将看到未送达的订单是如何被拒绝的。之后转到 Order 模块,选择发票的订单选项卡,然后点击增加:

validation_en010.png

它将显示一个视窗,列表中有可选择的订单。选择两张,其中一张尚未送达,然后点击增加:

validation_en013.png


已送达的订单会添加而另一个订单会被拒绝,并且产生以下消息:

validation_en017.png

总结

您已经有使用 @EntityValidator 的验证了。这并不难,但有点“冗长”,因为为了添加两行代码就得编写一个新的类。不过,这是一个很大的突破。在下一章,我们将看一些使用此验证更简单的方法。

下载本课源代码

对这节课有什么问题吗? 前往论譠 一切都顺利吗? 前往第十九章