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

Я запускаю веб-приложение в 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 ко всему объекту домена и добавьте туда ограничения проверки, но в настоящее время мой код настроен на прием отдельных параметров, как показано выше.

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

3 ответа

Решение

Там нет ничего встроенного, чтобы сделать это, пока нет. В текущих версиях выпуска вам все равно нужно будет использовать 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 и т. д., будет привязан к данным. Это достигается для простых случаев, просто сопоставляя имена параметров запроса с именами свойств бинов и вызывающими сеттерами. @ModelAttribute это просто личный стиль, в данном случае он ничего не делает. Интеграция JSR-303 с @Valid по параметру метода подключается через WebDataBinder, Если вы используете @RequestBody вы используете объектный маршаллер, основанный на типе контента, который весна определяет для тела запроса (обычно только из заголовка http.) Сервлет диспетчера (AnnotationMethodHandlerAdapter на самом деле) нет способа "щелкнуть переключателем валидации" для любого произвольного маршаллера. Он просто передает содержимое веб-запроса в конвертер сообщений и возвращает объект. Объект BindingResult не генерируется, поэтому в любом случае устанавливать ошибки некуда.

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

Похоже, что теперь это возможно (пробовал в Spring 4.1.2), см. https://raymondhlee.wordpress.com/2015/08/29/validating-spring-mvc-request-mapping-method-parameters/

Выписка из страницы выше:

  1. Добавьте MethodValidationPostProcessor в класс Spring @Configuration:

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

  3. Используйте @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;
    

    }

  4. Обрабатывать ConstraintViolationException в методе @ExceptionHandler

Если у вас есть несколько параметров запроса, которые должны быть проверены (с помощью HETP GET или POST). Вы также можете создать собственный класс модели и использовать @Valid вместе с @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;
    }

    ...
}

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

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