Spring MVC: объясните, пожалуйста, разницу между @RequestParam и @ModelAttribute
Я новичок в Spring MVC. Пожалуйста, помогите мне распаковать документацию.
Documentation
Spring Документация MVC заявляет (основное внимание):
-
@ModelAttribute
в аргументе метода указывает, что аргумент должен быть извлечен из модели. Если в модели нет, аргумент должен быть сначала создан, а затем добавлен в модель. После присутствия в модели поля аргументов должны быть заполнены из всех параметров запроса, имеющих соответствующие имена. Класс WebDataBinder сопоставляет имена параметров запроса - включая параметры строки запроса и поля формы - для моделирования полей атрибутов по имени.
-
@RequestParam
связывает параметры запроса с параметром метода в вашем контроллере.
Отказ от ответственности /Clarifier
Я знаю, что @ModelAttribute
и @RequestParam
не одно и то же, не являются взаимоисключающими, не выполняют одну и ту же роль и могут использоваться одновременно, как в this вопрос - действительно, @RequestParam
можно использовать для заполнения полей @ModelAttribute
. Мой вопрос больше ориентирован на разницу между их внутренними разработками.
Вопрос:
В чем разница между @ModelAttribute
(используется для аргумента метода, а не метода) и @RequestParam
? В частности:
- Источник: У
@RequestParam
и @ModelAttribute
есть тот же источник
информация/население, т.е. параметры запроса в URL-адресе, которые могут быть представлены как элементы формы/модели, которые были POST
ed?
- Использование: Правильно ли выбраны переменные, полученные с помощью
@RequestParam
(если они не переданы в модель), а переменные, полученные с помощью @ModelAttribute
, автоматически отправляются в возвращаемую модель?
Или в очень простых примерах кодирования, какова реальная рабочая разница между этими двумя примерами?
Пример 1: @RequestParam
:
// foo and bar are thrown away, and are just used (e.g.) to control flow?
@RequestMapping(method = RequestMethod.POST)
public String testFooBar(@RequestParam("foo") String foo,
@RequestParam("bar") String bar, ModelMap model) {
try {
doStuff(foo, bar);
}
// other code
}
Пример 2: @ModelAttribute
:
// FOOBAR CLASS
// Fields could of course be explicitly populated from parameters by @RequestParam
public class FooBar{
private String foo;
private String bar;
// plus set() and get() methods
}
// CONTROLLER
// Foo and Bar become part of the model to be returned for the next view?
@RequestMapping(method = RequestMethod.POST)
public String setupForm(@ModelAttribute("fooBar") FooBar foobar) {
String foo = fooBar.getFoo();
String bar = fooBar.getBar();
try {
doStuff(foo, bar);
}
// other code
}
Мое настоящее понимание:
@ModelAttribute
и @RequestParam
оба опросят параметры запроса для информации, но они используют эту информацию по-разному:
-
@RequestParam
просто заполняет автономные переменные (которые, конечно же, могут быть полями в классе @ModelAttribute
). Эти переменные будут выброшены, когда контроллер будет выполнен, если они не были отправлены в модель.
-
@ModelAttribute
заполняет поля класса, который затем заполняет атрибут модели, который будет передан обратно в представление
Правильно ли это?
Ответы
Ответ 1
@RequestParam
просто заполняет автономные переменные (которые, конечно, могут быть полями в классе @ModelAttribute
). Эти переменные будут выброшены, когда контроллер будет выполнен, если только они не были загружены в модель.
Не путайте слово "модель" с сеансом. HTTP-разговор обычно: HTTP.GET
, ответ сервера, затем HTTP.POST
. Когда вы используете аннотацию @ModelAttribute
, вы всегда создаете экземпляр того, что вы аннотировали, и это заставляет вас думать, что "подача вещи в модель" может привести к тому, что переменные будут всплывать. Это неверно, как только HttpServletRequest
закончил, эти переменные больше не должны быть частью разговора браузера/сервера, если они не были сохранены в сеансе.
@ModelAttribute
заполняет поля класса, который затем заполняет атрибут модели, который будет передан обратно в представление
Да! Чтобы быть верным, @ModelAttribute
сообщает Spring использовать связующее веб-данные по умолчанию для заполнения экземпляра чего-либо данными из HttpServletRequest
. Выбор для передачи этих данных обратно в представление зависит от программиста. Когда у вас есть метод, аннотированный с помощью @ModelAttribute
, он вызывается каждый раз, когда код попадает в этот сервлет. Когда у вас есть @ModelAttribute
как один из параметров метода, мы говорим о привязке данных к входящей Http-форме.
Вызов @RequestParam
- это ярлык для выражения request.getParameter("foo")
; под капотом Java HttpServletRequest
позволяет вам получать значения из объекта запроса, выполняя поиск ключа- > значение. Возвращаемое значение имеет тип Object. Это то, что вы набрали бы много, если бы вы не использовали Spring в своем веб-приложении.
Spring, затем эта абстракция сделает шаг вперед, когда вы начнете использовать @ModelAttribute
. В этой аннотации используется понятие привязки данных. Цель привязки данных заключается в том, что код в вашем контроллере не должен вызывать request.getParameter("foo1")
для каждого элемента формы. Представьте, что у вас есть веб-форма с 5 полями. Без привязки данных программист должен вручную извлечь и проверить каждое из этих полей. Программист должен убедиться, что запрос содержит свойство, что значение свойства существует, и что значение свойства имеет тип, ожидаемый для каждого поля. Использование @ModelAttribute
сообщает Spring выполнить эту работу для вас.
Если вы комментируете метод в своем контроллере с помощью @ModelAttribute("fooBar") FooBar fooBar
Экземпляр FooBar
всегда будет создан Spring и указан в вашем методе. Когда вступает в действие привязка данных, это когда эта аннотация используется в параметрах метода; Spring смотрит экземпляр HttpServletRequest
и видит, может ли он соответствовать данным в запросе правильному свойству экземпляра FooBar
. Это основано на соглашении свойств java, где у вас есть поле типа foo
и общедоступные геттеры и сеттеры, называемые getFoo
и setFoo
. Это может показаться волшебным, но если вы нарушите соглашение, ваша привязка данных Spring перестанет работать, потому что он не сможет узнать, где привязать данные из вашего HttpServletRequest
. Вы все равно получите экземпляр FooBar
, но свойства не будут заданы никакими значениями из запроса.
Ответ 2
@ModelAttribute
аннотированные параметры обрабатываются зарегистрированными ServletModelAttributeMethodProcessor
(или ModelAttributeMethodProcessor
) и @RequestParam
аннотированными параметрами обрабатываются зарегистрированными RequestParamMethodArgumentResolver
или RequestParamMapMethodArgumentResolver
в зависимости от типа параметра.
Здесь объяснение того, как Spring использует эти HandlerMethodArgumentResolvers
для разрешения аргументов для ваших методов обработчика:
В обоих случаях @ModelAttribute
и @RequestParam
значения, подлежащие привязке, извлекаются из ServletRequest
параметров.
Вы можете посмотреть исходный код упомянутых выше типов, но вот простые детали.
Для @ModelAttribute
, Spring создаст экземпляр типа параметра. Он проверит поля этого экземпляра и попытается привязать значения параметров к ним на основе стратегии именования/сглаживания, состоящей из имени @ModelAttribute
и имен полей. Обычно он использует группу экземпляров Converter
для преобразования из String
(значения параметров всегда String
) для любого типа целевого поля Integer
, Date
и т.д. Вы также можете зарегистрировать свой собственный Converter
типы для пользовательских преобразований. Вы также можете вставлять типы POJO.
Для @RequestParam
Spring будут использовать те же экземпляры Converter
для преобразования из значений параметров непосредственно в тип аннотированных параметров.
Обратите внимание, что значения параметров не выбрасываются. Они сохраняются в HttpServletRequest
для продолжительности цикла обработки запроса контейнера. Вы всегда можете получить к ним доступ через соответствующие методы.
Ответ 3
@ModelAttribute
(параметр) загружает атрибут модели из @SessionAttributes
или из @ModelAttribute
(метод).
Вам не нужно просто связывать значения с запросом, но он будет делать это после загрузки из @SessionAttributes
.
@RequestParam
связывает параметр запроса с объектом.
Ответ 4
Когда аннотация используется на уровне метода, она указывает, что целью этого метода является добавление одного или нескольких атрибутов модели. Такие методы поддерживают те же типы аргументов, что и методы @RequestMapping
, но не могут быть сопоставлены непосредственно с запросами.
@ModelAttribute
public void addAttributes(Model model) {
model.addAttribute("msg", "Welcome to the Netherlands!");
}
Метод, который добавляет атрибут msg ко всем моделям, определенным в классе контроллера.
Spring -MVC всегда будет делать вызов первым для этого метода, прежде чем он вызовет любые методы обработчика запросов. То есть, методы @ModelAttribute вызывается до того, как будут вызваны методы контроллера, аннотированные с помощью @RequestMapping. Логика последовательности состоит в том, что объект модели должен быть создан до того, как любая обработка начнется внутри методов контроллера.
Также важно, чтобы вы комментировали соответствующий класс как @ControllerAdvice. Таким образом, вы можете добавлять значения в Model, которые будут определены как глобальные. Это фактически означает, что для каждого запроса существует значение по умолчанию для каждого метода в части ответа.
- В качестве аргумента метода
При использовании в качестве аргумента метода он указывает, что аргумент должен быть извлечен из модели. если нет, он должен быть сначала создан, а затем добавлен в модель и один раз представлен в модели, поля аргументов должны быть заполнены из всех параметров запроса, имеющих соответствующие имена.
В фрагменте кода, который следует за атрибутом пользовательской модели, заполняется данными из формы, переданной в конечную точку addUser. Spring MVC делает это за кулисами перед вызовом метода отправки:
**@RequestMapping**(value = "/addUser", method = RequestMethod.POST)
public String submit(@ModelAttribute("user") User user) {
return "userView";
}
Таким образом, он связывает данные формы с bean. Контроллер, аннотированный с помощью @RequestMapping, может иметь пользовательский аргумент класса, аннотированный с помощью @ModelAttribute.
Это то, что обычно называют связыванием данных в Spring -MVC, общем механизме, который избавляет вас от необходимости отдельно анализировать каждое поле формы.
Ответ 5
@ModelAttribute
: связывает весь объект Java (например, Employee). поддерживает несколько параметров запроса
@RequestParam
: связывает один параметр запроса (например, firstName)
В целом,
@RequestParam
лучше всего читать небольшое количество параметров.
@ModelAttribute
используется, когда у вас есть форма с большим количеством полей.
и
@ModelAttribute
предоставляет дополнительные функции, такие как привязка данных, проверка и предварительная подготовка формы.