级联 bean 验证 2.0 不适用于 Map 中的嵌套对象
Cascaded bean validation 2.0 not working with nested object inside Map
不过,这个问题已经得到解答我很感兴趣为什么 @Validated
需要 Map<String, @Valid Employee>
. [=22= 的工作级联验证]
更新 2:为了更深入的理解,我找到了那些帖子 (,Two and Three),这解释了需要 @Validated
来激活方法水平验证。借助于此,可以验证集合,因为它们不是经过验证的 JavaBeans (JSR 303)。
解决方案:我已经用工作代码示例更新了我的代码片段和我的存储库。我所要做的就是用 @Validated
注释我的控制器并在 Employee
中添加一些 getter。 MethodValidationPostProcessor
完全没有必要。
更新:我更新了我的问题并分叉了 Spring Boot Rest 示例以添加最小 Rest API 来演示:
Github Repo。
示例值在 README.md!
内
我有一个 Spring Boot 2 API 来存放一些员工。我可以传递一个 Employee
或一个 Map<String, Employee>
.
@Validated //this is the solution to activate map validation
@RestController
class EmployeeController {
@PostMapping("/employees")
List<Employee> newEmployee(@RequestBody @Valid Employee newEmployee) {
...
}
@PostMapping("/employees/bulk")
List<Employee> newEmployee(@RequestBody Map<String, @Valid Employee>
newEmployees) {
...
}
}
员工存在一些内部静态 类 也需要验证:
public class Employee {
@NotBlank
public final String name;
@Valid
public final EmployeeRole role;
@JsonCreator
public Employee(@JsonProperty("name") String name,
@JsonProperty("role") EmployeeRole role) {
this.name = name;
this.role = role;
}
// getters
public static class EmployeeRole {
@NotBlank
public String rolename;
@Min(0)
public int rating;
@JsonCreator
public EmployeeRole(@JsonProperty("rolename") String rolename,
@JsonProperty("rating") int rating) {
this.rolename = rolename;
this.rating = rating;
}
// getters
}
}
目前,单个请求的验证有效,但我的批量请求无效。据我所知,这应该可以通过 Bean 验证 2.0 实现。
你知道我做错了什么吗?我需要编写自定义验证程序吗?
要使其正常工作,您必须执行以下操作:
Add MethodValidationPostProcessor
bean to configuration
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
Add @Validated
to your EmployeeController
@Validated
@RestController
public class EmployeeController {}'
Add @Valid
to Map
or to Employee
public List<Employee> newEmployee(@RequestBody @Valid Map<String, Employee> newEmployees) {}
public List<Employee> newEmployee(@RequestBody Map<String, @Valid Employee> newEmployees) {}
就是这样。这是整个 EmployeeController
:
@Validated
@RestController
public class EmployeeController {
@PostMapping("/employees")
public List<Employee> newEmployee(@RequestBody @Valid Employee newEmployee) {
return Collections.singletonList(newEmployee);
}
@PostMapping("/employees/bulk")
public List<Employee> newEmployee(@RequestBody @Valid Map<String, Employee> newEmployees) {
return new ArrayList<>(newEmployees.values());
}
}
和SpringBoot配置文件
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
希望对你有帮助。
spring系统中有两种验证。
- A: spring boot controller methods parameter validation, only works for the http post request body data in controller with
@Valid
or @Validated
aside
- B:方法级别验证,适用于任何方法参数和 return 值
@Validated
on class 和 @Valid
除了要验证的值
我们可以看到A更窄,B更常见。我想从两个方面回答这个问题。
1 答案在代码中
如this post中所述,more detail
部分,A和B通过调用不同的方法通过aop触发方法增强
org.hibernate.validator.internal.engine.ValidatorImpl
,这就导致了差异。
- 通过
RequestResponseBodyMethodProcessor
调用ValidatorImpl
中的validate
方法
- B call 通过
MethodValidationInterceptor
调用 ValidatorImpl
中的 validateParameters
方法
它们是不同的方法,具有不同的功能,所以会导致不同的结果。看完这两种方法你就可以找到答案了。
2 个答案在规范中
JSR-303 定义了我们上面讨论的方法的功能。
validate
方法在validation method part, and the implementation must obey the logic defined in validation routine中有解释,其中声明将对对象的所有可达字段执行所有约束验证,这就是为什么[=24=的元素] 对象(或其他集合实例)无法通过此方法验证 - 集合的元素不是集合实例的字段。
但是validateParameters
,JSR-303实际上并没有把它作为主要话题放在Appendix C. Proposal for method-level validation
中。它提供了一些描述:
The constraints declarations evaluated are the constraints hosted on the parameters of the method or constructor. If @Valid is placed on a parameter, constraints declared on the object itself are considered.
validateReturnedValue evaluates the constraints hosted on the method itself. If @Valid is placed on the method, the constraints declared on the object itself are considered.
public @NotNull String saveItem(@Valid @NotNull Item item, @Max(23) BigDecimal price)
In the previous example,
- item is validated against @NotNull and all the constraints it hosts
- price is validated against @Max(23)
- the result of saveItem is validated against @NotNull
并惊呼Bean Validation providers are free to implement this proposal as a specific extension
。据我所知,Hibernate Validation
项目实现了这个方法,使约束作用于对象本身,以及集合对象的元素。
3 一些抱怨
我不知道为什么 spring 框架的家伙在 RequestResponseBodyMethodProcessor
中调用 validate
,导致很多相关问题出现在 Whosebug 中。也许只是因为http post body 数据通常是表单数据,自然可以用java bean 来表示。如果是我,我会调用RequestResponseBodyMethodProcessor
里的validateParametes
方便使用
不过,这个问题已经得到解答我很感兴趣为什么 @Validated
需要 Map<String, @Valid Employee>
. [=22= 的工作级联验证]
更新 2:为了更深入的理解,我找到了那些帖子 (@Validated
来激活方法水平验证。借助于此,可以验证集合,因为它们不是经过验证的 JavaBeans (JSR 303)。
解决方案:我已经用工作代码示例更新了我的代码片段和我的存储库。我所要做的就是用 @Validated
注释我的控制器并在 Employee
中添加一些 getter。 MethodValidationPostProcessor
完全没有必要。
更新:我更新了我的问题并分叉了 Spring Boot Rest 示例以添加最小 Rest API 来演示:
Github Repo。 示例值在 README.md!
内我有一个 Spring Boot 2 API 来存放一些员工。我可以传递一个 Employee
或一个 Map<String, Employee>
.
@Validated //this is the solution to activate map validation
@RestController
class EmployeeController {
@PostMapping("/employees")
List<Employee> newEmployee(@RequestBody @Valid Employee newEmployee) {
...
}
@PostMapping("/employees/bulk")
List<Employee> newEmployee(@RequestBody Map<String, @Valid Employee>
newEmployees) {
...
}
}
员工存在一些内部静态 类 也需要验证:
public class Employee {
@NotBlank
public final String name;
@Valid
public final EmployeeRole role;
@JsonCreator
public Employee(@JsonProperty("name") String name,
@JsonProperty("role") EmployeeRole role) {
this.name = name;
this.role = role;
}
// getters
public static class EmployeeRole {
@NotBlank
public String rolename;
@Min(0)
public int rating;
@JsonCreator
public EmployeeRole(@JsonProperty("rolename") String rolename,
@JsonProperty("rating") int rating) {
this.rolename = rolename;
this.rating = rating;
}
// getters
}
}
目前,单个请求的验证有效,但我的批量请求无效。据我所知,这应该可以通过 Bean 验证 2.0 实现。
你知道我做错了什么吗?我需要编写自定义验证程序吗?
要使其正常工作,您必须执行以下操作:
Add
MethodValidationPostProcessor
bean to configuration
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
Add
@Validated
to yourEmployeeController
@Validated
@RestController
public class EmployeeController {}'
Add
@Valid
toMap
or toEmployee
public List<Employee> newEmployee(@RequestBody @Valid Map<String, Employee> newEmployees) {}
public List<Employee> newEmployee(@RequestBody Map<String, @Valid Employee> newEmployees) {}
就是这样。这是整个 EmployeeController
:
@Validated
@RestController
public class EmployeeController {
@PostMapping("/employees")
public List<Employee> newEmployee(@RequestBody @Valid Employee newEmployee) {
return Collections.singletonList(newEmployee);
}
@PostMapping("/employees/bulk")
public List<Employee> newEmployee(@RequestBody @Valid Map<String, Employee> newEmployees) {
return new ArrayList<>(newEmployees.values());
}
}
和SpringBoot配置文件
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
希望对你有帮助。
spring系统中有两种验证。
- A: spring boot controller methods parameter validation, only works for the http post request body data in controller with
@Valid
or@Validated
aside - B:方法级别验证,适用于任何方法参数和 return 值
@Validated
on class 和@Valid
除了要验证的值
我们可以看到A更窄,B更常见。我想从两个方面回答这个问题。
1 答案在代码中
如this post中所述,more detail
部分,A和B通过调用不同的方法通过aop触发方法增强
org.hibernate.validator.internal.engine.ValidatorImpl
,这就导致了差异。
- 通过
RequestResponseBodyMethodProcessor
调用 - B call 通过
MethodValidationInterceptor
调用
ValidatorImpl
中的validate
方法
ValidatorImpl
中的 validateParameters
方法
它们是不同的方法,具有不同的功能,所以会导致不同的结果。看完这两种方法你就可以找到答案了。
2 个答案在规范中
JSR-303 定义了我们上面讨论的方法的功能。
validate
方法在validation method part, and the implementation must obey the logic defined in validation routine中有解释,其中声明将对对象的所有可达字段执行所有约束验证,这就是为什么[=24=的元素] 对象(或其他集合实例)无法通过此方法验证 - 集合的元素不是集合实例的字段。
但是validateParameters
,JSR-303实际上并没有把它作为主要话题放在Appendix C. Proposal for method-level validation
中。它提供了一些描述:
The constraints declarations evaluated are the constraints hosted on the parameters of the method or constructor. If @Valid is placed on a parameter, constraints declared on the object itself are considered.
validateReturnedValue evaluates the constraints hosted on the method itself. If @Valid is placed on the method, the constraints declared on the object itself are considered.
public @NotNull String saveItem(@Valid @NotNull Item item, @Max(23) BigDecimal price)
In the previous example,
- item is validated against @NotNull and all the constraints it hosts
- price is validated against @Max(23)
- the result of saveItem is validated against @NotNull
并惊呼Bean Validation providers are free to implement this proposal as a specific extension
。据我所知,Hibernate Validation
项目实现了这个方法,使约束作用于对象本身,以及集合对象的元素。
3 一些抱怨
我不知道为什么 spring 框架的家伙在 RequestResponseBodyMethodProcessor
中调用 validate
,导致很多相关问题出现在 Whosebug 中。也许只是因为http post body 数据通常是表单数据,自然可以用java bean 来表示。如果是我,我会调用RequestResponseBodyMethodProcessor
里的validateParametes
方便使用