Spring Web MVC - проверка отдельных параметров запроса

Я запускаю webapp в Spring Web MVC 3.0, и у меня есть несколько методов контроллера, чьи подписи примерно следующие:

@RequestMapping(value = "/{level1}/{level2}/foo", method = RequestMethod.POST)
public ModelAndView createFoo(@PathVariable long level1,
        @PathVariable long level2,
        @RequestParam("foo_name") String fooname,
        @RequestParam(value = "description", required = false) String description);

Я хотел бы добавить некоторую проверку - например, description должен быть ограничен определенной длиной или fooname должен содержать только определенные символы. Если эта проверка не удалась, я хочу вернуть сообщение пользователю, а не просто отбросить какое-то неконтролируемое исключение (что произойдет в любом случае, если я пропущу данные до уровня DAO). Я знаю JSR303, но не работал с ним и не совсем понимаю, как применить его в контексте Spring.

Из того, что я понимаю, другим вариантом было бы привязать @RequestBody ко всему объекту домена и добавить туда ограничения проверки, но в настоящее время мой код настроен для принятия отдельных параметров, как показано выше.

Каков самый простой способ применения валидации для ввода параметров с использованием этого подхода?

Ответ 1

Там ничего не создано, не пока. В версиях текущей версии вам все равно придется использовать WebDataBinder для привязки ваших параметров к объекту, если вы хотите автоматическую проверку. Это стоит учиться, если вы используете SpringMVC, даже если это не ваш первый выбор для этой задачи.

Это выглядит примерно так:

public ModelAndView createFoo(@PathVariable long level1,
        @PathVariable long level2,
        @Valid @ModelAttribute() FooWrapper fooWrapper,
        BindingResult errors) {
  if (errors.hasErrors() {
     //handle errors, can just return if using Spring form:error tags.
  }
}

public static class FooWrapper {
  @NotNull
  @Size(max=32)
  private String fooName;
  private String description;
//getset
}

Если у вас есть Hibernate Validator 4 или более поздняя версия вашего пути к классам и используйте настройку диспетчера по умолчанию, он должен "Просто работать".

Редактирование с тех пор, как комментарии стали большими:

Любой объект, который в вашей сигнатуре метода, который не является одним из "ожидаемых" Spring, знает, как вводить, например HttpRequest, ModelMap и т.д., получит привязку данных. Это выполняется для простых случаев, просто сопоставляя имена параметров запроса с именами свойств bean и вызывающими сеттерами. @ModelAttribute есть только персональный стиль, в этом случае он ничего не делает. Интеграция JSR-303 с параметром @Valid по параметру метода проходит через WebDataBinder. Если вы используете @RequestBody, вы используете маршаллер объекта на основе типа контента Spring определяет для тела запроса (обычно только из заголовка http.) Сервлет диспетчера (AnnotationMethodHandlerAdapter действительно) не имеет способ "перевернуть переключатель проверки" для любого произвольного маршаллера. Он просто передает содержимое веб-запроса вместе с конвертером сообщений и возвращает объект. Объект BindingResult не генерируется, поэтому в любом случае не нужно устанавливать Ошибки.

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

Ответ 2

Теперь это возможно (рекомендуется с Spring 4.1.2), см. https://raymondhlee.wordpress.com/2015/08/29/validating-spring-mvc-request-mapping-method-parameters/

Извлечение сверху страницы:

  • Добавить метод MethodValidationPostProcessor в класс Spring @Configuration:

    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }
    
  • Добавить @Validated в класс контроллера

  • Используйте @Size перед @RequestParam

    @RequestMapping("/hi")
    public String sayHi(@Size(max = 10, message = "name should at most 10 characters long") @RequestParam("name") String name) {
        return "Hi " + name;
    

    }

  • Обработка исключений ConstraintViolationException в методе @ExceptionHandler

Ответ 3

Если у вас есть несколько параметров запроса, которые необходимо проверить (с помощью Http GET или POST). Вы могли бы также создать класс пользовательской модели и использовать @ Действительный вместе с @ ModelAttribute для проверки параметров. Таким образом вы можете использовать Hibernate Validator или javax.validator api для проверки параметров. Это происходит примерно так:

Метод запроса:

@RequestMapping(value="/doSomething", method=RequestMethod.GET)
public Model dosomething(@Valid @ModelAttribute ModelRequest modelRequest, BindingResult result, Model model) {

    if (result.hasErrors()) {
        throw new SomeException("invalid request params");
    }

    //to access the request params
    modelRequest.getFirstParam();
    modelRequest.getSecondParam();

    ...   
}

Класс ModelRequest:

class ModelRequest {

    @NotNull
    private String firstParam;

    @Size(min = 1, max = 10, message = "You messed up!")
    private String secondParam;

    //Setters and getters

    public void setFirstParam (String firstParam) {
        this.firstParam = firstParam;
    }

    public String getFirstParam() {
        return firstParam;
    }

    ...
}

Надеюсь, что это поможет.