我正在尝试使用JSR-303 Bean Validation API
和Spring's Validator
的组合为Sping Boot 端点实现一些自定义验证逻辑。
基于Validator
类图,似乎可以扩展CustomValidatorBean
、SpringValidatorAdapter
或LocalValidatorFactoryBean
中的一个,以便在重写的方法validate(Object target, Errors errors)
中添加一些自定义验证逻辑。
。
然而,如果我创建一个扩展这三个类中任何一个的验证器并使用@InitBinder
注册它,它的validate(Object target, Errors errors)
方法永远不会被调用,也不会执行任何验证。如果我删除@InitBinder
,那么默认的Spring验证器将执行JSR-303 Bean Validation
。
REST控制器:
@RestController
public class PersonEndpoint {
@InitBinder("person")
protected void initBinder(WebDataBinder binder) {
binder.setValidator(new PersonValidator());
}
@RequestMapping(path = "/person", method = RequestMethod.PUT)
public ResponseEntity<Person> add(@Valid @RequestBody Person person) {
person = personService.save(person);
return ResponseEntity.ok().body(person);
}
}
自定义验证器:
public class PersonValidator extends CustomValidatorBean {
@Override
public boolean supports(Class<?> clazz) {
return Person.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
super.validate(target, errors);
System.out.println("PersonValidator.validate() target="+ target +" errors="+ errors);
}
}
如果我的验证器实现了org.springframework.validation.Validator
,那么它的validate(Object target, Errors errors)
方法会被调用,但JSR-303 Bean Validation不会在此之前执行。我可以实现我的自定义JSR-303验证,类似于SpringValidatorAdapter
实现其JSR-303 Bean Validation的方式,但必须有一种方法来扩展它:
@Override
public void validate(Object target, Errors errors) {
if (this.targetValidator != null) {
processConstraintViolations(this.targetValidator.validate(target), errors);
}
}
我已经研究过使用自定义JSR-303约束来避免同时使用org.springframework.validation.Validator
,但必须有一种方法使自定义验证器工作。
Spring validation documentation在结合这两个方面并不是很清楚:
应用程序还可以为每个DataBinder示例注册额外的Spring Validator示例,如第9.8.3节“配置DataBinder”中所述。这对于在不使用注解的情况下插入验证逻辑可能很有用。
然后,稍后将涉及配置多个Validator
示例:
DataBinder还可以通过dataBinder.addValidators和dataBinder. replaceValidators配置多个Validator示例。当将全局配置的Bean Validation与DataBinder示例上本地配置的Spring Validator组合时,这很有用。请参阅???
Sping Boot 1.4.0版本
2条答案
按热度按时间vfhzx4xs1#
这个问题可以通过扩展LocalValidatorFactoryBean来解决,你可以覆盖这个类中的
validate
方法,给出你想要的任何行为。在我的例子中,我需要在同一个Controller中的不同方法中使用JSR-303和自定义验证器,通常建议使用@InitBinder,但这对我的情况是不够的,因为InitBinder在Model和Validator之间进行绑定(如果您使用@RequestBody,则InitBinder仅用于一个模型和每个Controller的一个验证器)。
控制器
自定义验证程序
要验证的类
CustomLocalValidatorFactoryBean
配置应用程序
/test
端点的输入:/test
端点的输出:/test2
端点的输入:输出到
/test2
端点:我希望这对你有帮助。
qlckcl4x2#
Per @M.代努姆-使用addValidators()而不是setValidator()做到了这一点。我也同意使用JSR-303,专门用于跨字段验证的基于@AssertTrue方法的注解,可能是一个更干净的解决方案。代码示例可在https://github.com/pavelfomin/spring-boot-rest-example/tree/feature/custom-validator中获得。在示例中,中间名验证通过定制的Spring验证器执行,而姓氏验证由默认的JSR 303验证器处理。