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

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

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

文档

Spring MVC Documentation 状态(强调我的):

免责声明/澄清

我知道@ModelAttribute@RequestParam不是一回事,不互斥,作用不同,可以同时使用,如this question - 事实上,@RequestParam 可用于填充 @ModelAttribute 的字段。我的问题更倾向于他们内部运作方式的不同。

问题:

@ModelAttribute(用于方法参数,而不是方法)和@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
  }

示例 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 just populates stand-alone variables (which may of course be fields in a @ModelAttribute class). These variables will be thrown away when the Controller is done, unless they have been fed into the model.

不要将 "model" 与会话混淆。 http会话一般是:HTTP.GET,服务器响应,然后是HTTP.POST。当您使用 @ModelAttribute 注释时,您总是在构造您注释的任何内容的实例,这就是让您认为 'feeding things to the model' 可能会使变量保留的原因。这是不正确的,一旦 HttpServletRequest 完成,这些变量不应再成为 browser/server 对话的一部分,除非它们已保存在会话中。

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

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

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

当您开始使用 @ModelAttribute 时,

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

如果您在控制器中用 @ModelAttribute("fooBar") FooBar fooBar 注释一个方法 FooBar 的实例将 总是 由 Spring 构造并提供到你的方法。数据绑定发挥作用的地方是在方法的参数中使用此注释时; Spring 查看 HttpServletRequest 的实例,看看它是否可以在 FooBar 的实例上匹配到右侧 属性 请求中的数据。这是基于 java 属性约定,其中您有一个字段,例如 foo 和 public getter 和 setter,称为 getFoosetFoo。这可能看起来很神奇,但如果您要打破惯例,您的 Spring 数据绑定将停止工作,因为它无法知道 何处 来绑定来自您的 HttpServletRequest 您仍会获得 FooBar 的实例,但不会将属性设置为请求中的任何值。

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

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

  • Form submit in Spring MVC 3 - explanation

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

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

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

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

请注意,参数值不是 "thrown away"。在容器的请求处理周期期间,它们存储在 HttpServletRequest 中。您可以随时通过 appropriate methods.

访问它们

@ModelAttribute (参数)@SessionAttributes@ModelAttribute (方法)[= 加载模型属性23=].

您不需要它只是为了绑定来自请求的值,但它会在从 @SessionAttributes.

加载后执行此操作

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

  • 在方法级别

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

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

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

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

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

  • 作为方法参数

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

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

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

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

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

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

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

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

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

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