Spring: привязка объекта с и без @ModelAttribute

Я новичок в Spring и регистрирую пользователя. Мне это понравилось.

@RequestMapping("/register")
    public String register(@ModelAttribute User user,BindingResult result){
       if(!result.hasErrors()){
         userSerive.register(user);
       }
     return "welcome";
}

Это сработало отлично, но проблема здесь в том, что мне не нужен этот объект user на моей странице welcome.jsp, поэтому зачем делать объект модели более тяжелым. Поэтому я пробовал без @ModelAttribute, это также работает для меня, как показано ниже.

@RequestMapping("/register")
    public String register(User user,BindingResult result){
       if(!result.hasErrors()){
         userSerive.register(user);
       }
     return "welcome";
}

Итак, я просто хочу знать, что за плюсы и минусы обоих и , что является лучшей практикой, если мне действительно не нужен объект user в jsp. Является ли @ModelAttribute любая другая вещь, кроме добавления объекта к модели, которая Spring неявная привязка не делает. Is @ModelAttribute более безопасный способ привязки или иначе?

Я хочу классифицировать свой запрос в следующем 4-х типах запроса. Какая разница с и без @ModelAttribute, если мне не нужно отправлять данные в поле зрения, а мой запрос - любой из <

  • строка запроса, т.е. данные формы в GET
  • запрашивать полезную нагрузку или тело, т.е. данные формы в POST
  • данные json в ajaxified GET requst
  • данные json в POST requst - я думаю, это не было бы связью ни в одном из них. @RequestBody.

Ответ 1

Вероятно (см. ниже...) нет различия в поведении между двумя сигнатурами метода в вашем случае.

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

@ModelAttribute можно использовать для настройки имени атрибута, например. @ModelAttribute("theUser"), или дать подсказку читателю вашего кода, что этот аргумент используется в представлении. Но, как вы говорите, ни один из них не применяется в вашем случае использования.

Точно такой же код в Spring будет использоваться для заполнения аргумента независимо от того, используете ли вы аннотацию @ModelAttribute или нет - данный код org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.

Поэтому для меня больше смысла использовать подпись public String register(User user, BindingResult result) в вашем коде. Добавление аннотации @ModelAttribute к аргументам метода, которые не требуются в модели, может смущать людей, читающих ваш код.


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

аргументы метода в методах обработчика Spring заполняются экземплярами HandlerMethodArgumentResolver. Они настраиваются и, в свою очередь, предпринимаются попытки для каждого параметра.

Решатели аргументов метода обработчика по умолчанию выглядят следующим образом (см. RequestMappingHandlerAdapter):

resolvers.add(new ServletModelAttributeMethodProcessor(false));

...

resolvers.add(new ServletModelAttributeMethodProcessor(true));

Если вы должны добавить свой собственный в середине, например. a UserHandlerMethodArgumentResolver, вы можете использовать @ModelAttribute, чтобы сообщить Spring обрабатывать определенный аргумент по умолчанию, а не использовать свой собственный класс распознавания аргументов.

Ответ 2

Помимо добавления объекта в Model, Spring MVC использует его для предоставления связанного объекта методу Controller, где вы можете его использовать, в вашем случае для "регистрации".

И да @ModelAtttribute является самым безопасным и лучшим способом в Spring MVC для привязки входящих сообщений к объекту.

Ответ 3

Этот вопрос очень полезен, но я не вижу ответа здесь правильно ответить на вопрос.

Я прочитал больше потоков в stackoverflow и нашел, что это очень полезно: fooobar.com/questions/24439/...

Для себя как решить, какой из них использовать, если мне нужна привязка и я не хочу хранить объект параметра в модели, тогда не используйте @ModelAttribute.

Ответ 4

Как описано в документации Spring MVC - аннотация @ModelAttribute может использоваться для методов или аргументов метода. И, конечно же, мы можем одновременно использовать оба контроллера.

аннотация метода

@ModelAttribute("person")
public Person getPerson(){
    return new Person();
}

Цель такого метода - добавить атрибут в модель. Таким образом, в нашем случае ключ человека будет иметь объект-объект как значение в Модели. Методы @ModelAttribute в контроллере вызываются перед методами @RequestMapping внутри одного контроллера.

Аргумент метода

public String processForm(@ModelAttribute("person") Person person){
    person.getStuff();
}

См. документацию Spring http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-modelattrib-method-args

Ответ 5

Отметьте этот пост здесь. Он содержит подробные сведения о ModelAttribute.

ModelAttribute может использоваться только с запрошенными формами данными запроса. Он не может связывать данные запроса json/xml с объектами данных. Для этого вам нужно будет использовать RequestBody.

Ответ 6

в дополнение к отличному ответу @ryanp, я бы хотел добавить:

для современного проекта spring mvc, наиболее вероятно, что он будет использовать аннотации, такие как @Controller и @RequestMapping и т.д., чтобы предоставить обработчик запроса, внутри, spring MVC использует RequestMappingHandlerAdapter.invokeHandlerMethod() для обработки запроса с пользователем предоставленный HandlerMethod. если вы посмотрите на RequestMappingHandlerAdapter, он настроит коллекцию аргумента resolver для подготовки аргумента для HandlerMethod, посмотрев на набор, вы поймете, как и в каком порядке spring запрос анализа синтаксиса MVC и заполняет предоставленные пользователем аргументы. поэтому здесь исходный код:

`` `Java

/**
 * Return the list of argument resolvers to use including built-in resolvers
 * and custom resolvers provided via {@link #setCustomArgumentResolvers}.
 */
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
    List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();

    // Annotation-based argument resolution
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
    resolvers.add(new RequestParamMapMethodArgumentResolver());
    resolvers.add(new PathVariableMethodArgumentResolver());
    resolvers.add(new PathVariableMapMethodArgumentResolver());
    resolvers.add(new MatrixVariableMethodArgumentResolver());
    resolvers.add(new MatrixVariableMapMethodArgumentResolver());
    resolvers.add(new ServletModelAttributeMethodProcessor(false));
    resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
    resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new RequestHeaderMapMethodArgumentResolver());
    resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new SessionAttributeMethodArgumentResolver());
    resolvers.add(new RequestAttributeMethodArgumentResolver());

    // Type-based argument resolution
    resolvers.add(new ServletRequestMethodArgumentResolver());
    resolvers.add(new ServletResponseMethodArgumentResolver());
    resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
    resolvers.add(new RedirectAttributesMethodArgumentResolver());
    resolvers.add(new ModelMethodProcessor());
    resolvers.add(new MapMethodProcessor());
    resolvers.add(new ErrorsMethodArgumentResolver());
    resolvers.add(new SessionStatusMethodArgumentResolver());
    resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

    // Custom arguments
    if (getCustomArgumentResolvers() != null) {
        resolvers.addAll(getCustomArgumentResolvers());
    }

    // Catch-all
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
    resolvers.add(new ServletModelAttributeMethodProcessor(true));

    return resolvers;
}

`` `

Стоит отметить, что все ресиверы Catch-all внизу. spring MVC использует те же самые два резольвера, которые обрабатывают @RequestParam и @ModelAttribute для обработки не аннотированных простых типов и аргументов типа pojo соответственно. Вот почему в тесте OP не имеет значения, есть ли @ModelAttribute или нет.

Позор, который он не сделал кристально чистым в ссылке spring MVC.