From 133b32989c366a088dea7d92a12a8e5d64a56fa6 Mon Sep 17 00:00:00 2001 From: xking Date: Tue, 18 Feb 2025 18:33:43 +0800 Subject: [PATCH] update jsr303 --- java/Jsr303校验.md | 97 +++++++++-- java/使用@Valid注解校验嵌套对象.md | 160 ------------------- 2 files changed, 80 insertions(+), 177 deletions(-) delete mode 100644 java/使用@Valid注解校验嵌套对象.md diff --git a/java/Jsr303校验.md b/java/Jsr303校验.md index 458c4e9..7922a20 100644 --- a/java/Jsr303校验.md +++ b/java/Jsr303校验.md @@ -2,7 +2,7 @@ ​ JSR303是Java为Bean数据合法性校验提供给的标准框架,已经包含在 JavaEE6.0 中、JSR303通过在Bean 属性中标注类似 @NotNull @Max 等标准的注解指定校验规则并通过标准的验证接口对 Bean进行验证 -### 注解 + ### JSR303中含有的注解 @@ -22,6 +22,8 @@ @Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式 ``` + + #### Hibernate Validator 附加的注解 ``` @@ -34,21 +36,82 @@ 注:HIbernate Validator是JSR303的一个参考实现,除了支持所有标准的校验注解外,另外HIbernate Validator还有JSR-380的实现 ``` -### 静态工具 手动校验BEAN - ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); - Validator validator = factory.getValidator(); - - AirportDTO dto = new AirportDTO(); - dto.setIataCode("PKX"); - dto.setThroughput("-1"); // 符合条件 - // data.setValue(1234567.789); // 不符合条件,整数部分超过6位 - // data.setValue(123456.78901); // 不符合条件,小数部分超过4位 - // data.setValue(-123.45); // 不符合条件,小于0 - - Set> validate = validator.validate(dto,Update.class); - for (ConstraintViolation violation : validate) { - System.out.println(violation.getMessage()); - } - } +### @Validated @Valid 有什么区别 + +`@Validated` 是spring 中提供的注解用于在添加该注解的方法、类上触发bean 校验。 + +`@Valid` java自身的注解 用于校验嵌套对象(在spring 环境中,添加该注解同样会触发bean 校验)。 + + + +### 对象嵌套校验 + +@Valid 校验嵌套对象 + +```java + +public class Project { + + @NotBlank(message = "Project title must be present") + @Size(min = 3, max = 20, message = "Project title size not valid") + private String title; + @Valid // 校验嵌套的对象 + private User owner; + +} + +public class User { + // 校验规则 + @NotBlank(message = "User name must be present") + @Size(min = 3, max = 50, message = "User name size not valid") + private String name; + + // 校验规则 + @NotBlank(message = "User email must be present") + @Email(message = "User email format is incorrect") + private String email; +} + + + +``` + +@Valid 校验可迭代对象 + +```java +// @Valid 定义在容器对象上 +@Valid +private List tasks; + +// @Valid (JSR303注解也可以)定义在泛型参数上 +private List<@Valid Task> tasks; + +private Map<@Valid User, @Valid Task> assignedTasks; +``` + + + + + +### Validator Api 手动校验BEAN + + +```java + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + Validator validator = factory.getValidator(); + + AirportDTO dto = new AirportDTO(); + dto.setIataCode("PKX"); + dto.setThroughput("-1"); // 符合条件 + // data.setValue(1234567.789); // 不符合条件,整数部分超过6位 + // data.setValue(123456.78901); // 不符合条件,小数部分超过4位 + // data.setValue(-123.45); // 不符合条件,小于0 + + Set> validate = validator.validate(dto,Update.class); + for (ConstraintViolation violation : validate) { + System.out.println(violation.getMessage()); + } + +``` diff --git a/java/使用@Valid注解校验嵌套对象.md b/java/使用@Valid注解校验嵌套对象.md deleted file mode 100644 index fb40e64..0000000 --- a/java/使用@Valid注解校验嵌套对象.md +++ /dev/null @@ -1,160 +0,0 @@ -# 使用 @Valid 注解校验嵌套对象 - -2024-07-29 - -[教程](https://springdoc.cn/categories/教程/) - -## 1、简介 - -本文将带你了解如何使用 `@Valid` 注解来验证对象及其嵌套的子对象。 - -当传入数据是基本数据类型,比如 `Integer` 或 `String` 时,验证数据可以很简单。然而,当传入信息是一个对象,特别是一个对象图时,验证可能会更加困难。幸运的是,`@Valid` 注解简化了对嵌套子对象的验证。 - -## 2、@Valid 注解是啥 - -`@Valid` 注解来自 [Jakarta Bean Validation](https://beanvalidation.org/) 规范,用于标记需要验证的特定参数。 - -使用该注解可确保传递给方法或存储在字段中的数据符合指定的验证规则。这有助于提高数据的完整性和一致性。 - -当在 *JavaBean* 的字段或方法上使用时,它会触发所有已定义的约束检查。Bean `Validation` API 中最常用的一些约束包括 `@NotNull`、`@NotBlank`、`@NotEmpty`、`@Size`、`@Email`、`@Pattern` 等。 - -## 3、在子对象上使用 @Valid 注解 - -首先,必须确定验证规则,并对字段应用前面提到的验证约束。 - -接下来,定义一个 `Project` 类,该类包含一个嵌套的 `User` 对象,并用 `@Valid` 注解来装饰该对象: - -```java -public class Project { - - @NotBlank(message = "Project title must be present") - @Size(min = 3, max = 20, message = "Project title size not valid") - private String title; - - @Valid // 校验嵌套的对象 - private User owner; - - // 构造函数、Getter、Setter 方法省略 - -} -public class User { - - // 校验规则 - @NotBlank(message = "User name must be present") - @Size(min = 3, max = 50, message = "User name size not valid") - private String name; - - // 校验规则 - @NotBlank(message = "User email must be present") - @Email(message = "User email format is incorrect") - private String email; - - // 构造函数、Getter、Setter 方法省略 - -} -``` - -之后,通过 `Validator` 实例的 `validate()` 方法来验证对象: - -```java -@Test -public void whenInvalidProjectAndUser_thenAssertConstraintViolations() { - Project project = new Project(null); - project.setOwner(new User(null, "invalid-email")); - - List messages = validate(project); - - assertEquals(3, messages.size()); - assertTrue(messages.contains("Project title must be present")); - assertTrue(messages.contains("User name must be present")); - assertTrue(messages.contains("User email format is incorrect")); -} - -private List validate(Project project) { - return validator.validate(project) - .stream() - .map(ConstraintViolation::getMessage) - .collect(Collectors.toList()); -} -``` - -此外,`@Valid` 注解可与 Spring 和 Jakarta EE 等框架完美配合。通过在 Controller 类的方法参数上使用该注解,可以在进入 Controller 方法之前就执行验证,这对于保持数据的一致性是再好不过了。 - -## 4、对象图验证 - -在对象有其他嵌套对象的情况下,需要使用一种称为对象图验证(*Object Graph Validation*)的机制。 - -该机制可验证对象图中相关对象的整个结构。所有使用 `@Valid` 注解的子对象(以及它们的子对象)在其父对象被验证时也会被验证。换句话说,验证在整个图中递归应用。 - -通过这种图遍历,可以得到一个 `ConstraintViolations` 集合,其中包含嵌套对象的所有验证失败的行为。 - -由于递归验证图中的每个对象,因此可能会遇到循环引用的问题,即对象在循环中相互引用。这可能会导致死循环,不断重复验证相同的对象。 - -幸运的是,*Jakarta Bean Validation* 包含定义验证路径的概念,即从根(ROOT)对象开始的 `@Valid` 关联序列。该实现跟踪已在当前路径中验证的每个实例,从根对象开始。如果同一实例在给定导航路径中出现多次,验证会忽略它,从而防止死循环。 - -## 5、在子对象上使用注解 - -接下来看看,如何在嵌套实例、集合和容器对象中的泛型参数上使用 `@Valid`。 - -### 5.1、使用 @Valid 验证嵌套的实例 - -验证嵌套实例的一种方法是使用字段访问策略,就像上一个示例中验证 `Project` 内部嵌套的用户 `User` 一样。只需用 `@Valid` 注解装饰字段,该实例就会添加到导航路径中: - -```java -@Valid -private User owner; -``` - -同样,验证嵌套实例的另一种方法是使用属性访问策略,这意味着可以在访问属性的 `getter` 方法上添加 `@Valid`: - -```java -@Valid -public User getOwner() { - return owner; -} -``` - -### 5.2、使用 @Valid 验证可迭代数据 - -集合、数组或 `java.lang.Iterebale` 接口的任何其他实现都可以使用 `@Valid` 注解。此时,会按照相同的规则对 `Iterable` 的每个元素进行验证。 - -注意,如果验证的是 `java.util.Map` 接口的实现,那么默认情况下只有 `Value` 会被验证。如果你确实需要对 `Key` 也进行验证,那么可以给 `Key` 也添加 `@Valid` 注解。 - -如下,对 `Map` 中的 `Key` 和 `Value` 都进行校验: - -```java -private Map<@Valid User, @Valid Task> assignedTasks; -``` - -### 5.3、在容器对象和泛型参数上使用注解 - -在容器对象和泛型参数上应用注解非常相似: - -```java -// @Valid 定义在容器对象上 -@Valid -private List tasks; - -// @Valid 定义在泛型参数上 -private List<@Valid Task> tasks; -``` - -第一个示例是在容器上使用注解,而第二个示例是直接在泛型参数上使用注解。在这种情况下,两者并无区别,都能按照预期运行。原则上,应该避免在两个地方都使用注解,因为这可能导致容器元素被验证两次。 - -如你所见,注解的使用是灵活的,但也有翻车的情况。例如,在嵌套泛型容器的情况下,要验证容器中的对象,就必须在内部容器的泛型引用上添加注解。 - -如下,一个嵌套在 `Map` 中的 `List`,需要在其泛型添加注解: - -```java -private Map> taskByType; -``` - -## 6、总结 - -本文介绍了什么是 `@Valid` 注解、如何使用它对子对象执行验证以及对象图验证的工作原理。 - -`@Valid` 注解是一个功能强大的工具,可以在不同的地方使用它来确保事物按照预期进行验证。它能自动检查对象图中的每个需要验证对象,使我们的工作更加轻松。 - ------- - -Ref:`https://www.baeldung.com/java-valid-annotation-child-objects` \ No newline at end of file