尽管已回答了这个问题,但我很感兴趣,为什么@Validated
的工作级联验证需要Map<String, @Valid Employee>
。
更新2 :为了更深入地了解,我发现了这些帖子(One,Two和Three),它们说明了{{1 }}需要激活方法级别验证。借助此方法,可以验证集合,因为它们不是经过验证的JavaBean(JSR 303)。
解决方案:我已经使用有效的代码示例更新了代码段和存储库。我要做的就是用@Validated
注释我的控制器,并在@Validated
中添加一些吸气剂。完全不需要Employee
。
更新:我已经更新了问题,并添加了Spring Boot Rest示例以添加一个最小的Rest API来演示:
Github Repo。 示例值在README.md中!
我有一个Spring Boot 2 API来存储一些员工。我可以传递一个MethodValidationPostProcessor
或Employee
。
Map<String, Employee>
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) {
...
}
}
目前,可以验证单个请求,但不能验证我的批量请求。据我所知,使用Bean验证2.0应该可以做到这一点。
您知道我做错了吗?我需要编写自定义验证器吗?
答案 0 :(得分:2)
要使其正常工作,您必须执行以下操作:
将
MethodValidationPostProcessor
bean添加到配置
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
将
@Validated
添加到您的EmployeeController
@Validated
@RestController
public class EmployeeController {}'
将
@Valid
添加到Map
或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();
}
}
希望它对您有帮助。
答案 1 :(得分:1)
spring系统中有两种验证方式。
@Valid
或@Validated
@Validated
和@Valid
并保留待验证的值我们可以看到A更狭窄,而B更常见。我想从两个方面回答这个问题。
如this post的more detail
部分所述,A和B通过调用aop中的不同方法来通过aop触发方法增强。
org.hibernate.validator.internal.engine.ValidatorImpl
,导致差异。
validate
在ValidatorImpl
中调用RequestResponseBodyMethodProcessor
方法validateParameters
调用ValidatorImpl
中的MethodValidationInterceptor
方法它们是具有不同功能的不同方法,因此导致不同的结果。您可以通过阅读两种方法找到答案。
JSR-303定义了我们上面讨论的方法的功能。
validate
方法在validation method部分中进行了说明,实现必须遵守validation routine中定义的逻辑,在该逻辑中,声明将对所有可到达的对象执行所有约束验证。 List
对象(或其他集合实例)的元素无法通过此方法验证的原因-集合的元素不是集合实例的字段。
但是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
项目实现了此方法,使约束作用于对象本身以及集合对象的元素。
我不知道为什么Spring框架人员在validate
中调用RequestResponseBodyMethodProcessor
,使很多相关问题出现在stackoverflow中。也许只是因为http post正文数据通常是表单数据,并且可以自然地由java bean表示。如果是我,我会在validateParametes
中呼叫RequestResponseBodyMethodProcessor
,以方便使用。