问题
I know about @Valid
annotation to instruct spring to validate for example a Controller argument according to JSR-303 in such this example:
@GetMapping("/test")
public TestDTO testDTO(@Valid TestDTO testDTO){
return testDTO;
}
But I would like to be able to configure Spring in some way to enable validation in all my controllers without specify explicitly the @Valid
annotation.
Is that possible in any way? Some Spring configuration? Making use of AOP?...
回答1:
I have finally came across with a working solution which may be not the optimal from the point of view of Spring configuration (as I said I'm Spring beginner).
The idea was to modify the argument resolvers (the ones that implement HandlerMethodArgumentResolver
), replacing the argument resolver associated to arguments with a @RequestBody
annotation. Creating an inherited class from the default one (which is RequestResponseBodyMethodProcessor
) and overriding a method in the class hierarchy which efectively determines if perform a validation or not (based in the presence of @Valid
, @Validated
, @ValidXxxxxx
annotations as the default behaviour), making to always validate with no further check.
So here is the code (I'm using Java 8 BTW):
Extend RequestResponseBodyMethodProcessor
to define validation strategy (in this case, always validate):
public class MyRequestResponseBodyMethodProcessor extends RequestResponseBodyMethodProcessor {
public MyRequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters) {
super(converters);
}
@Override
protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
binder.validate(); // always validating @RequestMapping annotated parameters ;)
}
}
Define a @Configuration
class where to replace default argument resolver:
@Configuration
public class MyValidationAdapterConfigurer {
@Autowired
private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
// Injecting your own resolver
@Autowired
private RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor;
@PostConstruct
public void init() {
// Don't know why but, removing the target resolver and adding the injected one to the end does not work!
// Must be something related with the resolvers ordering. So just replacing the target in the same position.
final List<HandlerMethodArgumentResolver> mangledResolvers = requestMappingHandlerAdapter.getArgumentResolvers().stream()
.map(resolver -> resolver.getClass().equals(RequestResponseBodyMethodProcessor.class) ?
requestResponseBodyMethodProcessor: resolver)
.collect(Collectors.toList());
requestMappingHandlerAdapter.setArgumentResolvers(mangledResolvers);
}
}
Finally configure Spring to deliver your customized Bean in your Application configuration class:
@Configuration
@PropertySource("classpath:api.properties")
public class MyRestApiConfiguration {
@Bean
@Autowired
RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters) {
return new MyRequestResponseBodyMethodProcessor(converters);
}
}
回答2:
unfortunately there is no "legal" way to do it.
Furthermore @Valid
is not enough. You need also a BindingResult
method parameter to be able to check the validation result: bindingResult.hasErrors()
If you don't want to use BindingResult
, you could write your own Validator and throw an Exception in case of invalid input.
回答3:
It should be possible to do this however like Markus in the similar question I'm not sure I agree its solving an actual problem.
Without getting too far into the weeds, Spring performs validation as part of model binding within ModelAttributeMethodProcessor's validateIfApplicable method. Per the javadoc
Validate the model attribute if applicable. The default implementation checks for @javax.validation.Valid, Spring's Validated, and custom annotations whose name starts with "Valid".
To override this functionality you need to create a custom ModelAttributeMethodProcessor / ServletModelAttributeMethodProcessor. You then would need to register it as an argument resolver
public class ApplicationConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> argumentResolvers) {
// add your custom model attribute processor here
}
}
来源:https://stackoverflow.com/questions/44722000/how-to-spring-get-rid-of-validate-for-automatic-controller-validation