Получить пользовательские ошибки проверки в BindingResult

Я пытаюсь удалить повторяющийся код из моих контроллеров Spring, в частности, устраняя необходимость выполнять validator.validate(form, bindingResult) с самого начала многих моих функций.

У меня есть несколько классов с соответствующими классами валидатора, которые реализуют интерфейс валидатора Spring. Я искал вокруг, чтобы попытаться найти ответ, но мне трудно найти тот, который действительно соответствует этому.

Фрагмент класса формы лица с аннотированными атрибутами

public class Person {

   @Size(min=1, message = "Name missing")
   private String name;
   @Size(min=1, message = "Age missing")
   private String age;

   .... getters and setters etc.

Класс проверки личности

@Component
public class PersonValidator implements Validator {

@Override
public boolean supports(Class<?> clazz) {
    return Person.class.isAssignableFrom(clazz);
} 

@Override
public void validate(Object target, Errors errors) {
        errors.reject("No sir!");
    }
}

В идеале я хотел бы иметь все ошибки, содержащиеся в BindingResult, включая ошибки из класса валидатора. Так что, когда я использую аннотацию @Validated, мой BindingResult полностью заполняется всеми ошибками как из простых аннотаций, так и из пользовательского валидатора.

Желаемый результат

@RequestMapping(value = "/save", method=RequestMethod.POST)

public @ResponseBody String save(@Validated @RequestBody Person personForm, BindingResult bindingResult, HttpServletRequest request) 
{

    bindingResult.getAllErrors(); <-- fully pop with annotation and custom validator errors

Вместо:

@RequestMapping(value = "/save", method=RequestMethod.POST)

public @ResponseBody String save(@Validated @RequestBody Person personForm, BindingResult bindingResult, HttpServletRequest request) 
{

    personValidator.validate(person, bindingResult) <-- Populate bindingResult with customer validator errors, if any

    bindingResult.getAllErrors(); 

У кого-нибудь есть хорошие примеры, которыми они могут поделиться, чтобы обойти это?

Спасибо!

Вы можете создать Constraint annotation и реализовать ConstraintValidator вместо того, чтобы создавать уникальный валидатор для каждого класса. Создавая Constraint, вы можете аннотировать класс или его поля-члены класса, а затем использовать @Valid и BindingResult

Elyas Hadizadeh 21.08.2021 08:33
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
1
2 468
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

В качестве возможного решения вы можете определить свою собственную аннотацию и CustomConstraintValidator, которые будут реализовывать интерфейс ConstraintValidator<A extends Annotation, T>. В конце BindingResult будет содержать либо валидатор по умолчанию, либо ваши собственные ошибки валидатора. Здесь — хороший пример. Если я правильно понял ваш вопрос, конечно.

Ответ принят как подходящий

Вам нужно добавить валидатор в связыватель данных, чтобы несколько валидаторов работали. В коде добавьте метод @InitBinder и добавьте PersonValidator к WebDataBinder.

@InitBinder("personForm")
public void initBinder(WebDataBinder wdb) {
  wdb.addValidators(personValidator);
}

Связывает валидатор с объектом модели personForm.

Это настроит глобальное правило, согласно которому этот валидатор применяется ко всем привязкам/конверсиям. Если вы хотите ограничить это определенной моделью, вы можете указать название модели в @InitBinder.

@InitBinder
public void initBinder(WebDataBinder wdb) {
  wdb.addValidators(personValidator);
}

Спасибо - теперь это работает. Что произойдет, если мой контроллер имеет две функции, которые принимают разные типы форм? то есть PersonForm и AnimalForm. Я только что сделал это, и он выдает ошибку, когда я отправляю форму животного. После небольшого исследования кажется, что мне может понадобиться использовать ModelAttribute вместо RequestBody в объявлении моего метода. Однако я просто отправляю тело JSON, а не форму - немного не знаю, как действовать дальше! По крайней мере, я сейчас там на 75%!

ScoobyShnacks 26.03.2019 11:17

@InitBinder принимает значение типов объектов, к которым оно применяется. Таким образом, вы можете сделать @InitBinder(PersonForm.class), чтобы ограничить привязку к этому типу.

M. Deinum 26.03.2019 11:27

можете ли вы передать более одного класса в аннотацию InitBinder? то есть @InitBinder(PersonForm.class AnimalForm.class)?

ScoobyShnacks 27.03.2019 11:25

Да, если вы проверите документацию, вы увидите, что она принимает массив...

M. Deinum 27.03.2019 11:28

@InitBinder({"person"}) работает нормально, но когда я добавляю "животное" в этот массив строк и добавляю свой дополнительный валидатор в метод, я получаю сообщение об ошибке "Неверный тег для валидатора". Есть ли способ добавить несколько валидаторов здесь?

ScoobyShnacks 27.03.2019 12:30

Все валидаторы должны проверять один и тот же объект, и я сомневаюсь, что person и animal относятся к одному и тому же типу объекта. Поэтому вам понадобится отдельный метод для animal.

M. Deinum 27.03.2019 12:32

Давайте продолжить обсуждение в чате.

ScoobyShnacks 27.03.2019 12:34

Другие вопросы по теме