Проверка каскадного компонента 2.0 не работает с вложенным объектом внутри карты - PullRequest
3 голосов
/ 11 февраля 2020

Хотя, на этот вопрос был дан ответ, мне интересно, зачем @Validated необходим для работающей каскадной проверки Map<String, @Valid Employee>.

Обновление 2 : Для более глубокого понимания я нашел эти посты ( Один , Два и Три ), что объясняет, что @Validated необходим для активации уровня метода Проверка. С помощью этого коллекции могут быть проверены, поскольку они не являются JavaBeans, которые проверяются вместо этого (JSR 303).


Решение : я обновил свои фрагменты кода и мой репозиторий примерами рабочего кода. Все, что мне нужно сделать, это пометить мой контроллер с помощью @Validated и добавить несколько геттеров в Employee. MethodValidationPostProcessor вообще не требуется.

Обновление : я обновил свой вопрос и разобрал пример Spring Boot Rest, чтобы добавить минимальный API отдыха для демонстрации:

Github Repo . Примеры значений находятся внутри README.md!


У меня есть Spring Boot 2 API для хранения некоторых сотрудников. Я могу передать один Employee или Map<String, Employee>.

@Validated //this is the solution to activate map validation
@RestController
class EmployeeController {

  @PostMapping("/employees")
  List<Employee> newEmployee(@RequestBody @Valid Employee newEmployee) {
     ...
  }

  @PostMapping("/employees/bulk")
  List<Employee> newEmployee(@RequestBody Map<String, @Valid Employee> 
  newEmployees) {
     ...
  }
}

Сотрудник существует с некоторыми внутренними классами c, которые также должны быть проверены:

public class Employee {

    @NotBlank
    public final String name;
    @Valid
    public final EmployeeRole role;

    @JsonCreator
    public Employee(@JsonProperty("name") String name,
        @JsonProperty("role") EmployeeRole role) {

        this.name = name;
        this.role = role;
    }

    // getters

    public static class EmployeeRole {

        @NotBlank
        public String rolename;

        @Min(0)
        public int rating;

        @JsonCreator
        public EmployeeRole(@JsonProperty("rolename") String rolename,
            @JsonProperty("rating") int rating) {

            this.rolename = rolename;
            this.rating = rating;
        }

        // getters
    }
}


На данный момент проверка для отдельных запросов работает, но не для моих массовых запросов. Насколько я знаю, это возможно с помощью валидации Bean 2.0.

Знаете ли вы, что я сделал не так? Мне нужно написать собственный валидатор?

Ответы [ 2 ]

2 голосов
/ 11 февраля 2020

Чтобы это работало, вы должны сделать следующее:

Добавить MethodValidationPostProcessor компонент в конфигурацию

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
    return new MethodValidationPostProcessor();
}

Добавить @Validated к вашему EmployeeController

@Validated
@RestController
public class EmployeeController {}'

Добавьте @Valid к Map или Employee

public List<Employee> newEmployee(@RequestBody @Valid Map<String, Employee> newEmployees) {}   
public List<Employee> newEmployee(@RequestBody Map<String, @Valid Employee> newEmployees) {}

Вот и все. Это всего EmployeeController:

@Validated
@RestController
public class EmployeeController {

    @PostMapping("/employees")
    public List<Employee> newEmployee(@RequestBody @Valid Employee newEmployee) {
        return Collections.singletonList(newEmployee);
    }

    @PostMapping("/employees/bulk")
    public List<Employee> newEmployee(@RequestBody @Valid Map<String, Employee> newEmployees) {
        return new ArrayList<>(newEmployees.values());
    }
}

И конфигурационный файл SpringBoot

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }

}

Надеюсь, он вам поможет.

1 голос
/ 12 февраля 2020

В системе пружин есть два вида проверки.

  • A: Проверка параметров методов контроллера загрузочной пружины, работает только для данных тела http-запроса post в контроллере с @Valid или @Validated в сторону
  • B: проверка уровня метода, работает для любых параметров метода и возвращает значения с @Validated в классе и @Valid в сторону значений для проверки

Мы можем видеть что A более узкий, а B более распространенный. Я хотел бы ответить на вопрос по двум аспектам.

1 Ответы находятся в коде

Как описано в этом посте , часть more detail, A и B вызывает улучшение метода через aop, вызывая другой метод в org.hibernate.validator.internal.engine.ValidatorImpl, что приводит к разнице.

  • Вызов метода validate в ValidatorImpl через RequestResponseBodyMethodProcessor
  • Вызов метода B validateParameters метод в ValidatorImpl через MethodValidationInterceptor

Это разные методы с разными функциями, поэтому они приводят к разным результатам. Вы можете найти ответ, прочитав два метода.

2 Ответы содержатся в спецификации

. JSR-303 определяет функции методов, которые мы обсуждали выше. Метод

validate описан в разделе метод проверки , и реализация должна подчиняться логике c, определенной в подпрограмме проверки , в которой говорится, что он выполнит всю проверку ограничений для всех достижимых полей объекта, поэтому элемент List object (или другой экземпляр коллекции) не может быть проверен с помощью этого метода - элементы коллекции не являются полями экземпляра коллекции.

Но validateParameters, JSR-303 на самом деле не рассматривает его как основной топи c и помещает его в Appendix C. Proposal for method-level validation. Это дает некоторое описание:

The constraints declarations evaluated are the constraints hosted on the parameters of the method or constructor. If @Valid is placed on a parameter, constraints declared on the object itself are considered.

validateReturnedValue evaluates the constraints hosted on the method itself. If @Valid is placed on the method, the constraints declared on the object itself are considered.

public @NotNull String saveItem(@Valid @NotNull Item item, @Max(23) BigDecimal price)

In the previous example,

- item is validated against @NotNull and all the constraints it hosts
- price is validated against @Max(23)
- the result of saveItem is validated against @NotNull

и восклицает, что Bean Validation providers are free to implement this proposal as a specific extension. Насколько я знаю, проект Hibernate Validation реализует этот метод, заставляет работать ограничения для самого объекта и элемента объекта коллекции.

3 Некоторые жалуются

Я не знаю почему ребята из фреймворка Spring звонят validate в RequestResponseBodyMethodProcessor, поэтому многие вопросы появляются в stackoverflow. Может быть, это потому, что данные тела сообщения http обычно являются данными формы и могут быть представлены в виде бина java естественным образом. Если это я, я позвоню по номеру validateParametes in RequestResponseBodyMethodProcessor для удобства использования.

...