Подтвердить что ты не робот

Spring MVC @Valid Validation с пользовательским HandlerMethodArgumentResolver

Я хочу зарегистрировать пользовательский HandlerMethodArgumentResolver, который может обрабатывать следующее определение метода обработчика @Controller

@RequestMapping(method = RequestMethod.POST)
public String createDomain(@Valid Domain domain, BindingResult errors, @RequestParam("countryId") Long countryId) {

Я могу зарегистрировать свой резольвер, который просто создает объект Domain через параметры запроса, переопределяя addArgumentResolver() из WebMvcConfigurerAdapter. Когда Spring пытается разрешить параметр Domain, он проходит через свой список HandlerMethodArgumentResolver (их много) и выбирает первый, который supports() он.

В приведенном выше примере, хотя мой резольвер будет вызван, и мой аргумент Domain будет инициализирован, аннотация @Valid не будет обработана и преобразователем для BindingResult, a ErrorsMethodArgumentResolver завершится с ошибкой, так как для метода обработчика требуется @ModelAttribute, @RequestBody или @RequestPart аргумент, который у меня отсутствует.

Если я попытаюсь исправить это, добавив @ModelAttribute

@RequestMapping(method = RequestMethod.POST)
public String createDomain(@Valid @ModelAttribute Domain domain, BindingResult errors, @RequestParam("countryId") Long countryId) {

a HandlerMethodArgumentResolver, ModelAttributeMethodProcessor, сначала будет проверяться с помощью supports() и разрешить аргумент (с @ModelAttribute и @Valid) перед моим пользовательским преобразователем. BindingResult не будет работать, но у меня не будет своего пользовательского поведения создания на экземпляре Domain.

Я мог бы просто скопировать код для проверки и добавить к модели, что в ModelAttributeMethodProcessor, но я надеялся, что есть более простой способ разрешить мои параметры и выполнить проверку без добавления объекта к модели. Есть ли такой способ?

4b9b3361

Ответ 1

Хорошее описание проблемы, с которой вы столкнулись.

Я проверил код, который вы наметили, и пришел к тому же выводу, что у вас есть - нет встроенного способа иметь как настраиваемую HandlerMethodArgumentResolver так и @Valid связанную проверку, применяемую при этом time, единственный выбор - сделать то, что делает ModelAttributeMethodProcessor, чтобы проверить, имеет ли параметр аннотацию @Valid и вызывает код логики проверки достоверности.

Вероятно, вы можете получить HandlerMethodResolverArgumentResolver от ModelAttributeMethodProcessor и вызвать super.validateIfApplicable(..) по крайней мере таким образом, чтобы существующий код был задействован.

Ответ 2

Возможно, слишком поздно, но ваш HandlerMethodArgumentResolver получает объект WebDataBinderFactory в качестве последнего аргумента, а затем, чтобы подключить проверку, просто добавьте это в свою реализацию resolver:

Object resolvedObject = // your logic 
if(parameter.hasParameterAnnotation(Valid.class){
            binderFactory.createBinder(webRequest,resolvedObject,"resolvedObjectLogicalName").validate ();
}