Аннотация Spring MVC 3 Controller для onBind() – как?

Я обновляюсь с Spring 2.5 до Spring 3.2. У меня есть контроллер MVC, который ранее расширял CancellableFormController. Он объявил отдельно методы initBinder() и onBind(). Я реорганизовал контроллер, чтобы использовать аннотацию @Controller, и переключил переопределенный метод initBinder() на использование аннотации Spring MVC 3 @initBinder.

Мой конкретный вопрос заключается в том, что в Spring MVC 3 при обновлении с Spring 2.5 как реорганизовать переопределенный метод onBind() для использования эквивалента аннотации? Сигнатура существующего метода:

@Override
protected void onBind(HttpServletRequest request, Object command, BindException errors)  throws Exception {
    MyCommand cmd = (MyCommand) command;
    ....
}

Я подумал об использовании @initBinder() и поместил код ранее в onBind() внутри этого аннотированного метода. Но мое замешательство вот в чем:

  1. При этом будет ли код вызываться в то же время в общем процессе фреймворка, что и раньше?
  2. Как получить дескриптор объекта Command из аннотированного метода @initBinder.

Могу ли я просто объявить его как еще один параметр в сигнатуре метода, и среда Spring MVC гарантирует, что я получу копию? Похоже, что в старом методе onBind() объект Command уже создан (методом formBackingObject). Могу ли я с уверенностью предположить, что это также имеет место при использовании метода @initBinder?

Спасибо всем за некоторые идеи. Я пытаюсь ускорить процесс Spring MVC!

Моя существующая сигнатура метода @initBinder выглядит примерно так:

@InitBinder
protected void initBinder(WebDataBinder binder) {
    // register custom editor here.. etc
}

Я надеюсь, что смогу сделать что-то вроде:

@InitBinder
protected void initBinder(WebDataBinder binder, MyCommand cmd) {
   // register custom editor here.. etc
}

Является ли это стандартным передовым подходом для обновления метода cancellableformcontroller onBind() с использованием аннотаций?

Попытка, основанная на ответе, отмеченном как правильный, все еще не работает:

@InitBinder("myCommand")
protected void onBind(WebDataBinder binder) throws Exception {
    MyCommand cmd = (MyCommand) binder.getTarget();
    .... // do whatever was required here...
}

Обойти

Пожалуйста, смотрите мои комментарии ниже для нулевого флага. Создайте частный метод с той же логикой, что и в onBind(), а затем после проверки объекта команды в аннотированном методе onSubmit() (POST/GET) сделайте вызов ныне несуществующему методу onBind(), передав ваш объект Command в виде параметр. Что-то вроде следующего:

@RequestMapping(method=RequestMethod.POST) 
public ModelAndView onSubmit(@ModelAttribute("myCommand") MyCommand cmd, BindingResult result, <any other params> {
    
        new MyCommandValidator().validate(cmd, result);
        if (result.hasErrors()) {
            return new ModelAndView("context");
        }
        onBind(cmd, <any other params>);

        ... // do business stuff

}

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


person arcseldon    schedule 30.04.2013    source источник
comment
Прежде чем я отвечу: почему вы хотите получить доступ к объекту команды? Я почти уверен, что в текущем Spring MVC есть более автоматическое решение :)   -  person a better oliver    schedule 30.04.2013
comment
Спасибо, что нашли время и усилия, чтобы спросить. По сути, это унаследованный код (устаревшее приложение около 5 лет), поэтому точный контекст теряется. Из того, что я прочитал, исходной целью было проверить объект Command и прочитать несколько атрибутов, а затем, наконец, обновить некоторую информацию в объекте команды. Теперь, почему это должно было произойти в onBind(), а не в каком-то другом методе ловушки в процессе, не совсем ясно. Давайте просто предположим, что пользователь хотел убедиться, что объект команды был полностью обновлен во время привязки;) Знаете ли вы об эквивалентном механизме в Spring MVC 3 с аннотациями?   -  person arcseldon    schedule 30.04.2013
comment
@zeroflagL - см. комментарий выше.   -  person arcseldon    schedule 30.04.2013


Ответы (1)


Вы можете получить доступ к объекту команды с помощью binder.getTarget(). @InitBinder вызывается для каждого параметра модели метода контроллера. Предположим, следующий код

@RequestMapping("/somePath")
public String myMethod(@ModelAttribute("user") User user,
                       @ModelAttribute("info") Info info) {

Затем ваш метод initBinder вызывается как минимум дважды: для объекта User и для объекта Info. Чтобы он вызывался только для определенного объекта, добавьте имя модели:

@InitBinder("user")

Таким образом, он будет вызываться только для объекта User. Имейте в виду, однако, что метод все еще может вызываться более одного раза, в первый раз, даже если целевой объект имеет значение null.

Если вы хотите, чтобы некоторые поля не устанавливались автоматически, вы можете использовать setDisallowedFields() в своем initBinderметоде.

Если вы хотите выполнить некоторую проверку, позвольте JSR 303 (проверка компонентов) выполнить эту работу.

В зависимости от того, что вы хотите сделать, метод @ModelAttribute в вашем контроллере может быть решением:

@ModelAttribute("user")
public User createUser(HttpServletRequest request /*or whatever*/) {
  User user = new User();
  //check some parameters and set some attributes
  return user;
}

Создает пользовательский объект до привязки.

Последним решением может быть преобразователь сообщений или типов для вашего командного объекта, который создает объект из запроса. На самом деле это похоже на пример выше, но не зависит от контроллера, и нет привязки к объекту, созданному с помощью преобразователя.

person a better oliver    schedule 30.04.2013
comment
считаю, что первая часть вашего ответа - это именно то, что мне нужно было знать. Пожалуйста, дайте мне немного времени, чтобы обновить мой код и протестировать его. Все будет хорошо, я отмечу этот ответ как правильный. Оцените помощь!! - person arcseldon; 30.04.2013
comment
извините, что так долго обновляю мой код и проверяю ваше решение. Да, это правильный ответ, и он решил мою проблему. Должен обновить мой вопрос решением, которое я использовал на основе вашего решения. Спасибо! - person arcseldon; 06.05.2013
comment
хорошо, наконец, я обнаружил, что это не работает, как ожидалось. объект команды, возвращаемый из getTarget(), не содержит значений. В то время как с onBind() он передавал заполненные формы значения (как атрибуты внутри объекта команды) и вызывался до onSubmit(). - person arcseldon; 07.05.2013
comment
@user36123 user36123 он называется initBinder по какой-то причине;) Вот почему я предоставил еще несколько вариантов. Не могли бы вы опубликовать соответствующий код вашего текущего метода onBind()? Затем мы могли бы определить лучший путь миграции для вашего приложения. - person a better oliver; 07.05.2013
comment
zeroflagL - Еще раз спасибо за дополнительную информацию. В конечном итоге я добился того, что мне было нужно, просто создав в контроллере частный/защищенный метод, который содержал ту же логику, что и onBind ранее, и явно вызывая его с помощью аннотированного (POST) метода onSubmit(), передавая объект команды в качестве параметра. Это отговорка, и, возможно, не используются методы шаблона Spring Framework для получения точного времени, как раньше (хотя казалось, что onBind вызывается непосредственно перед onSubmit в старом контроллере), но в этом случае он удовлетворил мои конкретные требования. Еще раз спасибо. - person arcseldon; 09.05.2013