Java Spring MVC:请解释@RequestParam 和@ModelAttribute 之间的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29370581/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:52:48  来源:igfitidea点击:

Spring MVC: please explain difference between @RequestParam and @ModelAttribute

javaspringspring-mvcspring-annotations

提问by Lydia Ralph

I'm new to Spring MVC. Please help me unpack the documentation.

我是 Spring MVC 的新手。请帮我解开文档。

Documentation

文档

Spring MVC Documentationstates (emphasis mine):

Spring MVC 文档说明(重点是我的):

  • @ModelAttributeon a method argument indicates the argument should be retrieved from the model. If not present in the model, the argument should be instantiated first and then added to the model. Once present in the model, the argument's fields should be populated from all request parameters that have matching names. The WebDataBinder class matches request parameter names?—?including query string parameters and form fields?—?to model attribute fields by name.

  • @RequestParambinds request parameters to a method parameterin your controller.

  • @ModelAttribute在方法参数上表示应该从模型中检索参数。如果模型中不存在该参数,则应首先实例化该参数,然后将其添加到模型中。一旦出现在模型中,参数的字段应该从所有具有匹配名称的请求参数中填充。WebDataBinder 类匹配请求参数名称?—?包括查询字符串参数和表单字段?—?按名称对属性字段进行建模。

  • @RequestParam将请求参数绑定到控制器中的方法参数

Disclaimer / Clarifier

免责声明/澄清

I know that @ModelAttributeand @RequestParamare not the same thing, are not mutually exclusive, do not perform the same role, and can be used simultaneously, as in this question- indeed, @RequestParamcan be used to populate fields of @ModelAttribute. My question is more geared towards the difference between their internal workings.

我知道@ModelAttribute@RequestParam不是一回事,不是相互排斥的,不执行相同的角色,并且可以同时使用,就像在这个问题中一样- 事实上,@RequestParam可以用来填充@ModelAttribute. 我的问题更侧重于他们内部工作之间的差异。

Question:

题:

What is the difference between @ModelAttribute(used on a method argument, not method) and @RequestParam? Specifically:

@ModelAttribute(用于方法参数,而不是方法)和@RequestParam?之间有什么区别?具体来说:

  • Source:Do @RequestParamand @ModelAttributehave the same source of information / population, i.e. request parameters in URL, which may have been supplied as elements of a form / model that was POSTed?
  • Usage:Is it correct that variables retrieved with @RequestParamare thrown away (unless passed into a model), whereas variables retrieved with @ModelAttributeare automatically fed into the model to be returned?
  • 来源:是否@RequestParam@ModelAttribute具有相同的信息/人口来源,即 URL 中的请求参数,这些参数可能已作为已POST编辑的表单/模型的元素提供?
  • 用法:@RequestParam丢弃检索到的变量(除非传递到模型中)是否正确,而检索@ModelAttribute到的变量会自动输入模型以返回?

Or in very basic coding examples, what is the real working difference between these two examples?

或者在非常基本的编码示例中,这两个示例之间真正的工作区别是什么?

Example 1: @RequestParam:

示例 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
  }

Example 2: @ModelAttribute:

示例 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
}


My current understanding:

我目前的理解:

@ModelAttributeand @RequestParamboth interrogate the request parameters for information, but they use this information differently:

@ModelAttribute并且@RequestParam都询问请求参数以获取信息,但它们使用此信息的方式不同:

  • @RequestParamjust populates stand-alone variables (which may of course be fields in a @ModelAttributeclass). These variables will be thrown away when the Controller is done, unless they have been fed into the model.

  • @ModelAttributepopulates the fields of a class, which then populates an attribute of the model to be passed back to the view

  • @RequestParam只填充独立变量(当然可能是@ModelAttribute类中的字段)。当 Controller 完成时,这些变量将被丢弃,除非它们已被输入到模型中。

  • @ModelAttribute填充类的字段,然后填充要传递回视图的模型的属性

Is this correct?

这样对吗?

采纳答案by zmf

@RequestParamjust populates stand-alone variables (which may of course be fields in a @ModelAttributeclass). These variables will be thrown away when the Controller is done, unless they have been fed into the model.

@RequestParam只填充独立变量(当然可能是@ModelAttribute类中的字段)。当 Controller 完成时,这些变量将被丢弃,除非它们已被输入到模型中。

Don't confuse the word "model" with session. The http conversation is generally: HTTP.GET, server response, then HTTP.POST. When you have the @ModelAttributeannotation in use you are always constructing an instance of whatever you have annotated, this is what makes you think that 'feeding things to the model' might make variables stick around. This isn't correct, once the HttpServletRequesthas finished those variables should no longer be a part of the browser/server conversation unless they've been saved in a session.

不要将“模型”一词与会话混淆。http会话一般是:HTTP.GET,服务器响应,然后HTTP.POST。当您@ModelAttribute使用注释时,您总是在构建您已注释的任何实例,这就是让您认为“向模型提供内容”可能会使变量存在的原因。这是不正确的,一旦HttpServletRequest完成,这些变量不应再成为浏览器/服务器对话的一部分,除非它们已保存在会话中。

@ModelAttributepopulates the fields of a class, which then populates an attribute of the model to be passed back to the view

@ModelAttribute填充类的字段,然后填充要传递回视图的模型的属性

Yes! To be correct, @ModelAttributetells Spring to use its default web data binder to populate an instance of something with data from the HttpServletRequest. Choosing to pass this data back to the view is up to the programmer. When you have a method annotated with @ModelAttribute, it is being called every time code hits that servlet. When you have @ModelAttributeas one of the method's parameters, we are talking about incoming Http form data-binding.

是的!正确地说,@ModelAttribute告诉 Spring 使用其默认的 Web 数据绑定器来使用来自HttpServletRequest. 选择将此数据传递回视图取决于程序员。当您有一个用 注释的方法时@ModelAttribute,每次代码命中该 servlet 时都会调用它。当您@ModelAttribute作为方法的参数之一时,我们谈论的是传入的 Http 表单数据绑定。

Calling @RequestParamis a shortcut for saying request.getParameter("foo"); under the hood, Java's HttpServletRequestlets you get values from the request object by doing a key->value look up. The value returned is of type Object. This is what you would be typing a lot if you were not using Spring in your web application.

打电话@RequestParam是说的捷径request.getParameter("foo");在幕后,JavaHttpServletRequest允许您通过执行键-> 值查找从请求对象中获取值。返回的值是对象类型。如果您没有在 Web 应用程序中使用 Spring,这就是您要输入的内容。

Spring then takes this abstraction a step further when you start to use @ModelAttribute. This annotation employs the concept of data-binding. The goal of data-binding is that the code in your controller won't have to call request.getParameter("foo1"), for every form element. Imagine you have a web form with 5 fields. Without data-binding the programmer has to manually retrieve, and validate each of those fields. The programmer has to make sure that the request contains the property, that the property's value exists, and that the property's value is of the type expected for each field. Using @ModelAttributetells Spring to do this work for you.

当您开始使用@ModelAttribute. 这个注解使用了数据绑定的概念。数据绑定的目标是控制器中的代码不必request.getParameter("foo1")为每个表单元素调用, 。假设您有一个包含 5 个字段的 Web 表单。如果没有数据绑定,程序员必须手动检索和验证每个字段。程序员必须确保请求包含属性,属性的值存在,并且属性的值是每个字段所期望的类型。Using@ModelAttribute告诉 Spring 为您完成这项工作。

If you annotate a method in your controller with @ModelAttribute("fooBar") FooBar fooBarAn instance of FooBarwill alwaysbe constructed by Spring, and supplied to your method. Where the data binding comes into play, is when this annotation is used in a Method's parameters; Spring looks at the instance of HttpServletRequestand sees if it can match the data in the request to the right property on an instance of FooBar. This is based off the java properties convention, where you have a field such as fooand public getters and setters called getFooand setFoo. This might seem magic but if you were to break convention, your Spring data binding would stop working because it wouldn't be able to know whereto bind the data from your HttpServletRequestYou would still get an instance of FooBar, but the properties would not be set to any values from the request.

如果你在你的控制器中注释一个方法,@ModelAttribute("fooBar") FooBar fooBar一个实例FooBar始终由 Spring 构造,并提供给你的方法。数据绑定发挥作用的地方是在方法的参数中使用此注释时;Spring 查看 的实例HttpServletRequest并查看它是否可以将请求中的数据与 的实例上的正确属性匹配FooBar。这是基于关闭Java属性约定,那就是你有一个领域,如foo公共getter和setter叫getFoosetFoo。这可能看起来很神奇,但如果你打破惯例,你的 Spring 数据绑定将停止工作,因为它无法知道在哪里绑定你的数据HttpServletRequest你仍然会得到一个实例FooBar,但不会将属性设置为请求中的任何值。

回答by Sotirios Delimanolis

@ModelAttributeannotated parameters are handled by a registered ServletModelAttributeMethodProcessor(or ModelAttributeMethodProcessor) and @RequestParamannotated parameters are handled by a registered RequestParamMethodArgumentResolveror RequestParamMapMethodArgumentResolverdepending on the parameter type.

@ModelAttribute带注释的参数由注册的ServletModelAttributeMethodProcessor(或ModelAttributeMethodProcessor@RequestParam处理,带注释的参数由注册的RequestParamMethodArgumentResolverRequestParamMapMethodArgumentResolver取决于参数类型处理。

Here's an explanation of how Spring uses these HandlerMethodArgumentResolversto resolve arguments for your handler methods:

下面解释了 Spring 如何使用这些HandlerMethodArgumentResolvers来解析处理程序方法的参数:

In both cases, @ModelAttributeand @RequestParam, the values to be bound are retrieved from ServletRequestparameters.

在这两种情况下,@ModelAttribute@RequestParam,要绑定的值都是从ServletRequestparameters中检索的。

You can look at the source code of the types mentioned above, but here are the simple details.

您可以查看上面提到的类型的源代码,但这里是简单的细节。

For @ModelAttribute, Spring will create an instance of the parameter type. It will inspect the fields of that instance and attempt to bind parameter values to them based on a naming/aliasing strategy composed of the @ModelAttributename and the field names. It typically uses a group of Converterinstances to convert from String(parameter values are always Stringvalues) to whatever the target field type Integer, Date, etc. You can also register your own Convertertypes for custom conversions. You can also nest POJO types.

对于@ModelAttribute,Spring 将创建参数类型的实例。它将检查该实例的字段并尝试根据由@ModelAttribute名称和字段名称组成的命名/别名策略将参数值绑定到它们。它通常使用一组的Converter情况下,从转换String(参数值总是String值)到任何目标字段类型IntegerDate等等。你也可以注册自己的Converter类型定制的转换。您还可以嵌套 POJO 类型。

For @RequestParam, Spring will use the same Converterinstances to convert from the parameter values directly to the annotated parameter type.

对于@RequestParam,Spring 将使用相同的Converter实例将参数值直接转换为带注释的参数类型。

Note that parameter values are not "thrown away". They are stored in the HttpServletRequestfor the duration of the container's request processing cycle. You can always access them through the appropriate methods.

请注意,参数值不会被“丢弃”。它们存储在HttpServletRequest容器的请求处理周期的持续时间内。您始终可以通过适当的方法访问它们。

回答by Neil McGuigan

@ModelAttribute(parameter)loads a model attribute from @SessionAttributesor from @ModelAttribute(method).

@ModelAttribute(parameter)@SessionAttributes或从@ModelAttribute(method)加载模型属性。

You don't need it just to bind values from a request, but it will do that after loading from @SessionAttributes.

您不仅仅需要它来绑定请求中的值,但它会在从@SessionAttributes.

@RequestParambinds a request parameter to an object.

@RequestParam将请求参数绑定到对象。

回答by Kumar Abhishek

  • At the Method Level
  • 在方法层面

When the annotation is used at the method level it indicates the purpose of that method is to add one or more model attributes. Such methods support the same argument types as @RequestMappingmethods but that cannot be mapped directly to requests.

当在方法级别使用注释时,它表明该方法的目的是添加一个或多个模型属性。此类方法支持与方法相同的参数类型,@RequestMapping但不能直接映射到请求。

@ModelAttribute
public void addAttributes(Model model) {
    model.addAttribute("msg", "Welcome to the Netherlands!");
}

A method that adds an attribute named msg to all models defined in the controller class.

将名为 msg 的属性添加到控制器类中定义的所有模型的方法。

Spring-MVC will always make a call first to that method, before it calls any request handler methods. That is, @ModelAttribute methods are invoked before the controller methods annotated with @RequestMapping are invoked.The logic behind the sequence is that, the model object has to be created before any processing starts inside the controller methods.

Spring-MVC 将始终先调用该方法,然后再调用任何请求处理程序方法。也就是说,@ModelAttribute 方法在调用带有 @RequestMapping 注释的控制器方法之前被调用。该序列背后的逻辑是,必须在控制器方法内部开始任何处理之前创建模型对象。

It is also important that you annotate the respective class as @ControllerAdvice. Thus, you can add values in Model which will be identified as global. This actually means that for every request a default value exists, for every method in the response part.

将相应的类注释为 @ControllerAdvice 也很重要。因此,您可以在模型中添加将被标识为全局的值。这实际上意味着对于每个请求都有一个默认值,对于响应部分中的每个方法。

  • As a Method Argument
  • 作为方法参数

When used as a method argument, it indicates the argument should be retrieved from the model. if not present, it should be first instantiated and then added to the model and once present in the model, the arguments fields should be populated from all request parameters that have matching names.

当用作方法参数时,它表示应该从模型中检索参数。如果不存在,则应首先实例化,然后将其添加到模型中,一旦出现在模型中,则应从具有匹配名称的所有请求参数中填充参数字段。

In the code snippet that follows the user model attribute is populated with data from a form submitted to the addUser endpoint. Spring MVC does this behind the scenes before invoking the submit method:

在用户模型属性后面的代码片段中,填充了来自提交给 addUser 端点的表单的数据。Spring MVC 在调用 submit 方法之前在幕后执行此操作:

**@RequestMapping**(value = "/addUser", method = RequestMethod.POST)
public String submit(@ModelAttribute("user") User user) {
    return "userView";
}

So, it binds the form data with a bean. The controller annotated with @RequestMapping can have custom class argument(s) annotated with @ModelAttribute.

因此,它将表单数据与 bean 绑定。用@RequestMapping 注释的控制器可以有用@ModelAttribute 注释的自定义类参数。

This is what is commonly known as data binding in Spring-MVC, a common mechanism that saves you from having to parse each form field individually.

这就是 Spring-MVC 中通常所说的数据绑定,这是一种通用机制,使您不必单独解析每个表单字段。

回答by Harinath

@ModelAttribute: binds an entire Java object (like Employee). supports multiple request parameters

@ModelAttribute: 绑定整个 Java 对象(如 Employee)。支持多个请求参数

@RequestParam: binds a single request parameter (like firstName)

@RequestParam: 绑定单个请求参数(如 firstName)

In general,
@RequestParamis best for reading a small number of params.

一般来说,
@RequestParam最适合读取少量参数。

@ModelAttributeis used when you have a form with a large number of fields.

@ModelAttribute当您有一个包含大量字段的表单时使用。

and

@ModelAttributegives you additional features such as data binding, validation and form prepopulation.

@ModelAttribute为您提供附加功能,例如数据绑定、验证和表单预填充。