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

问题描述 投票:44回答:5

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

文档

Spring MVC Documentation州(强调我的):

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

免责声明/澄清

我知道@ModelAttribute@RequestParam不是同一个东西,不是相互排斥,不执行相同的角色,并且可以同时使用,如this question - 事实上,@RequestParam可以用来填充@ModelAttribute的字段。我的问题更多地是针对其内部运作之间的差异。

题:

@ModelAttribute(用于方法参数,而不是方法)和@RequestParam有什么区别?特别:

  • 来源:@RequestParam@ModelAttribute是否具有相同的信息/人口来源,即URL中的请求参数,这些参数可能是作为POSTed的表单/模型的元素提供的?
  • 用法:使用@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填充类的字段,然后填充要传递回视图的模型的属性

它是否正确?

java spring spring-mvc spring-annotations
5个回答
35
投票

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

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

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

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

调用@RequestParam是说request.getParameter("foo")的捷径;在引擎盖下,Java的HttpServletRequest允许您通过执行key-> value查找来从请求对象获取值。返回的值是Object类型。如果您没有在Web应用程序中使用Spring,那么这就是您要输入的内容。

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

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


3
投票

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

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

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

当您拥有包含大量字段的表单时,将使用@ModelAttribute

@ModelAttribute为您提供其他功能,如数据绑定,验证和表格预填充。


2
投票

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

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

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

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

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

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

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


0
投票

@ModelAttribute(参数)从@SessionAttributes@ModelAttribute(方法)加载模型属性。

您不需要它只是绑定请求中的值,但它会在从@SessionAttributes加载后执行此操作。

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


0
投票
  • 在方法级别

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

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

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

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

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

  • 作为方法论证

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

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

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.