openxava / 文档 / 第二十一章:自定义 Bean Validation 注解

课程: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

Table of contents

第二十一章:自定义 Bean Validation 注解
创建您自己的 Bean Validation 注解
在实体使用 Bean Validation
定义您自己的 ISBN 注解
使用 Apache Commons Validator 实现验证逻辑
总结
在上一章,您看到如何在移除时验证。在本章,您将了解到如何创建自定义的 Bean Validation 注解。

创建您自己的 Bean Validation 注解

至此所使用的验证方法对您应用程序所需的大多验证都是有用的。然而,有时您会遇到一些通用的验证,并且您会想要重复地使用它们。在这种情况下,定义您自己的 Bean Validation 注解可能是一个不错的选择。定义一个 Bean Validation 比较冗长,但是使用和重用很简单;只需向您的属性或类添加注解。
我们将学习如何创建一个 Bean Validation 验证器。

在实体使用 Bean Validation

这很容易。只需注解您的属性,如下:
@ISBN // 此注解表示该属性必须作为 ISBN 进行验证
String isbn;
只需将 @ISBN 添加到您的属性,它将在实体保存到数据库之前进行验证。问题是 @ISBN 并没有作为内置验证器包含在 Bean Validation 框架中。但这没什么大不了的,如果想要一个 @ISBN 注解,就创建它吧!我们现在将创建 @ISBN 验证注解。
首先,让我们为 Product 添加一个新的 isbn 属性。编辑您的 Product 类并将以下代码添加到其中:
@Column(length=13)
String isbn;
使用浏览器运行您的 Product 模块。会看到 isbn 属性已经存在。现在,可以添加验证。

定义您自己的 ISBN 注解

首先,在您的项目中创建一个名为 com.yourcompany.invoicing.annotations 的包。然后用鼠标右键单击它并选择 New > Annotation,如下所示:

validation_en020.png

它将显示一个对话框,输入 ISBN 作为注解名称,然后点击 Finish:

validation_en030.png


编写您最近创建的 ISBN 注解的代码,如下:
package com.yourcompany.invoicing.annotations; // 在注解包

import java.lang.annotation.*;
import javax.validation.*;
 
@Constraint(validatedBy = com.yourcompany.invoicing.validators.ISBNValidator.class)
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ISBN { // 一个常规 Java 注解的定义
 
    Class<?>[] groups() default{};
    Class<? extends Payload>[] payload() default{};
    String message() default "isbn_invalid"; // i18n 文件消息的 id
}
如您所见,这是一个常规注解的定义。 message 属性是在验证失败时向用户显示的消息,您可以直接编写消息或输入 i18n id。虽然我们提供一个默认消息:isbn_invalid。但开发者在使用注解时也可以指定自己的消息,这必须在 invoicing-messages_zh.properties 中添加:
isbn_invalid=ISBN 无效或不存在
@Constraint 指示具有验证逻辑的类。让我们编写 ISBNValidator 类。

使用 Apache Commons Validator 实现验证逻辑

我们将使用 ISBN 的验证逻辑编写 ISBNValidator 类并使用 Apache 的 Commons Validator ,而不是自己编写 ISBN 验证逻辑。 Commons Validator 包含电子邮件地址、日期、URL 等的验证算法。 commons-validator.jar 默认包含在 OpenXava 项目中,因此您无需进一步配置即可使用它。 ISBNValidator 的代码如下:
package com.yourcompany.invoicing.validators; // 在验证器包中

import javax.validation.*;
 
import com.yourcompany.invoicing.annotations.*;
import org.openxava.util.*;
 
public class ISBNValidator implements ConstraintValidator<ISBN, Object> { // 必须实现 ConstraintValidator
 
    private static org.apache.commons.validator.routines.ISBNValidator
        validator = // 来自Commons Validator 框架
            new org.apache.commons.validator.routines.ISBNValidator();
 
    public void initialize(ISBN isbn) {
 
    }
 
    // 包含验证逻辑
    public boolean isValid(Object value, ConstraintValidatorContext context) { 
        if (Is.empty(value)) return true;
        return validator.isValid(value.toString()); // 使用“Commons Validator”
    }
}
如您所见,验证器类必须实现 javax.validation 包中的 ConstraintValidator。这会强制您的验证器实现 initialize() 和 isValid()。 isValid() 方法包含验证逻辑。要注意的是,如果要验证的值为空,我们假定它是有效的。验证一个值何时存在是 @Required 等其他注解的责任。
在这种情况下,验证逻辑很简单,因为我们只从 Apache Commons Validator 中调用 ISBN 验证器。
@ISBN 已准备好。只需注解您的 isbn 属性。像:
@Column(length=13) @ISBN
String isbn;
在这情况,当您将类的代码保存时,@ISBN 的导入不会自动添加。这是因为还有另一个@ISBN 可用(来自OpenXava 包含的Hibernate Validator 库),所以OpenXava Studio 不知道该选择哪一个。不用担心,只需将鼠标放在@ISBN 注解上,将显示一个弹出窗口,其中包含几种可能的解决方案,选择 Import 'ISBN' (com.yourcompany.invoicing.annotations),以便将正确的导入添加到 Product 类:

validation_en035.png

现在,您可以试试模块,并验证您输入的 ISBN 值是否正确验证。恭喜!您编写了您的第一个 Bean Validation。并没那么难 :一个注解,一个类。
这个 @ISBN 足以在现实生活中使用。尽管如此,我们会尝试改进它,只是为了有机会尝试一些有趣的可能性。

总结

恭喜!您已经学到如何创建自己的 Bean Validation 注解。在下一章,您将学到如何从验证中调用 REST 服务。

下载本课源代码

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