假设我有一个这样的样本实体类:
public class Address {
...
}
和相应的验证器:
@Component
public AddressValidator implements Validator {
@Override
public boolean supports(Class<?> entityClass) {
return entityClass.equals(Address.class);
}
@Override
public void validate(Object obj, Errors errors) {
...
}
}
当我使用如下控制器时,一切正常:
@RestController
@RequestMapping("/addresses")
public class AddressController {
@Autowired
private AddressValidator validator;
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(validator);
}
@RequestMapping(method=POST)
public Long addNewAddress(@Valid @RequestBody Address address) {
...
}
}
但是,如果省略验证器注册部分(即以下内容),则不会执行验证。
@Autowired
private AddressValidator validator;
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(validator);
}
手动注册验证器似乎毫无意义。我可以指示Spring自动查找验证器(类似于查找控制器的方式)吗?
它是一个基于Spring Boot的应用程序。
答案 0 :(得分:2)
您可以使用gist或更低版本中的示例。我们的想法是拥有一个主要的CompositeValidator,它将成为所有Validator或SmartValidator实例的持有者。
它支持提示,也可以与Hibernate Annotation Validator(LocalValidatorFactoryBean)集成。并且每个特定模型可以有更多的验证器。
<强> CompositeValidator.java 强>
@Component
public class CompositeValidator implements SmartValidator {
@Autowired
private List<Validator> validators = Collections.emptyList();
@PostConstruct
public void init() {
Collections.sort(validators, AnnotationAwareOrderComparator.INSTANCE);
}
@Override
public boolean supports(Class<?> clazz) {
for (Validator validator : validators) {
if (validator.supports(clazz)) {
return true;
}
}
return false;
}
@Override
public void validate(Object target, Errors errors) {
validate(target, errors, javax.validation.groups.Default.class);
}
@Override
public void validate(Object target, Errors errors, Object... validationHints) {
Class<?> clazz = target.getClass();
for (Validator validator : validators) {
if (validator.supports(clazz)) {
if (validator instanceof SmartValidator) {
((SmartValidator) validator).validate(target, errors, validationHints);
} else {
validator.validate(target, errors);
}
}
}
}
}
<强> SomeController.java 强>
@Controller
@RequestMapping("/my/resources")
public class SomeController {
@RequestMapping(method = RequestMethod.POST)
public Object save(
@Validated(javax.validation.groups.Default.class) // this interface descriptor (class) is used by default
@RequestBody MyResource myResource
) { return null; }
}
Java配置
@Configuration
public class WebConfig {
/** used for Annotation based validation, it can be created by spring automaticaly and you don't do it manualy */
// @Bean
// public Validator jsr303Validator() {
// LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
// // validator.setValidationMessageSource(...);
// return validator;
// }
@Bean
public WebMvcConfigurerAdapter webMvcConfigurerAdapter() {
return new WebMvcConfigurerAdapter() {
@Autowired
private CompositeValidator validator;
@Override
public Validator getValidator() {
return validator;
}
}
}
或XML配置
<!-- used for Annotation based validation, it can be created by spring automaticaly and you don't do it manualy -->
<!--<bean id="jsr303Validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">-->
<!-- <property name="validationMessageSource" ref="messageSource"/>-->
<!--</bean>-->
<mvc:annotation-driven validator="compositeValidator">
//...
</mvc:annotation-driven>
答案 1 :(得分:1)
您可以配置全局验证器。
如果您使用基于Java的Spring配置和WebMvcConfigurationSupport,则可以覆盖getValidator()
/**
* Override this method to provide a custom {@link Validator}.
*/
protected Validator getValidator() {
return null;
}
您可以在全局WebBindingInitializer上调用setValidator(Validator)。这允许您跨所有@Controller类配置Validator实例。这可以通过使用Spring MVC命名空间轻松实现:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven validator="globalValidator"/>
</beans>
答案 2 :(得分:0)
我没有为此找到Spring解决方案的构建,但这就是我的工作。
我在spring java配置中声明我的验证器bean,如下所示:
@Bean
public Validator studentValidator(){
return new StudentValidator();
}
@Bean
public Validator carValidator(){
return new CarValidator();
}
然后我让所有控制器像这样扩展一个基本控制器:
public abstract class BaseController <T> {
public BaseController(List<Validator> validators) {
super();
this.validators = validators;
}
//Register all validators
@InitBinder
protected void initBinder(WebDataBinder binder) {
validators.stream().forEach(v->binder.addValidators(v));
}
}
此控制器的具体类获取通过依赖注入注入的List,如下所示:
@Controller
public class StudentController extends BaseController<Student>{
@Inject
public StudentController(List<Validator> validators) {
super(validators);
}
}
基本控制器使用@InitBinder回调方法注册所有验证器。
我很惊讶Spring并没有自动注册实现Validator接口的类路径中的所有对象。