# 2.3.1 声明验证规则

对于 Taco 类，希望确保 name 属性不是空的或 null 的，并且所选配料列表中至少有一项。下面的程序清单显示了一个更新后的 Taco 类，它使用 @NotNull 和 @Size 来声明这些验证规则。

{% code title="程序清单 2.10 为 Taco 域类添加验证" %}

```java
package tacos;
​
import java.util.List;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import lombok.Data;
​
@Data
public class Taco {
    
    @NotNull
    @Size(min=5, message="Name must be at least 5 characters long")
    private String name;
    
    @Size(min=1, message="You must choose at least 1 ingredient")
    private List<String> ingredients;
}
```

{% endcode %}

你会发现，除了要求 name 属性不为 null，同时你声明它应该有一个值是至少 5 个字符的长度。

当涉及到对提交玉米饼订单进行验证声明时，必须对 Order 类应用注解。对于地址的属性，只需要确保用户没有留下任何空白字段。对于这一点，将使用 Hibernate Validator 的 @NotBlank 注解。

支付领域的验证是一个比较奇特的存在。你不仅需要确保 ccNumber 属性不为空，还要确保它包含的是一个有效的信用卡号码的值。该 ccExpiration 属性必须符合 MM/YY（两位数的年/月）格式。而 ccCVV 属性必须是一个三位的数字。为了实现这种验证，需要使用一些其他的 Java Bean Validation API 注释，同时需要从 Hibernate Validator 集合中借用一些验证注解。下面程序清单列出了验证 Order 类所需要的改变。

{% code title="程序清单 2.11 验证 Order 字段" %}

```java
package tacos;
​
import javax.validation.constraints.Digits;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.CreditCardNumber;
import javax.validation.constraints.NotBlank;
import lombok.Data;
​
@Data
public class Order {
    
    @NotBlank(message="Name is required")
    private String name;
    
    @NotBlank(message="Street is required")
    private String street;
    
    @NotBlank(message="City is required")
    private String city;
    
    @NotBlank(message="State is required")
    private String state;
    
    @NotBlank(message="Zip code is required")
    private String zip;
    
    @CreditCardNumber(message="Not a valid credit card number")
    private String ccNumber;
    
    @Pattern(regexp="^(0[1-9]|1[0-2])([\\/])([1-9][0-9])$",
             message="Must be formatted MM/YY")
    private String ccExpiration;
    
    @Digits(integer=3, fraction=0, message="Invalid CVV")
    private String ccCVV;
}
```

{% endcode %}

可以看到，ccNumber 属性用 @CreditCardNumber 进行了注释。该注释声明属性的值必须是通过 Luhn 算法（<https://en.wikipedia.org/wiki/Luhn_algorithm>）检查过的有效信用卡号。这可以防止用户出错的数据和故意错误的数据，但不能保证信用卡号码实际上被分配到一个帐户，或该帐户可以用于交易。

不幸的是，没有现成的注释来验证 ccExpiration 属性的 MM/YY 格式。我已经应用了 @Pattern 注释，为它提供了一个正则表达式，以确保属性值符合所需的格式。如果想知道如何破译正则表达式，我建议查看许多在线正则表达式指南，包括 <http://www.regularexpressions.info/>。正则表达式语法是一门黑暗的艺术，当然也超出了本书的范围。

最后，用 @Digits 注释 ccCVV 属性，以确保值恰好包含三个数字。

所有的验证注释都包含一个消息属性，该属性定义了如果用户输入的信息不符合声明的验证规则的要求时将显示给用户的消息。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://potoyang.gitbook.io/spring-in-action-v5/di-2-zhang-kai-fa-web-ying-yong-cheng-xu/2.3-yan-zheng-biao-dan-shu-ru/2.3.1-sheng-ming-yan-zheng-gui-ze.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
