How to: Spring get rid of @Validate for automatic Controller validation?

ぃ、小莉子 提交于 2019-12-21 05:03:25

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!