【问题标题】:Spring MVC: please explain difference between @RequestParam and @ModelAttributeSpring MVC:请解释@RequestParam 和@ModelAttribute 之间的区别
【发布时间】:2015-06-04 21:46:11
【问题描述】:

我是 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 类中的字段)。这些变量将在 Controller 完成后被丢弃,除非它们已被输入到模型中。

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

这对吗?

【问题讨论】:

    标签: java spring spring-mvc spring-annotations


    【解决方案1】:

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

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

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

    是的!正确地说,@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 以及称为 getFoosetFoo 的公共 getter 和 setter。这可能看起来很神奇,但是如果您打破约定,您的 Spring 数据绑定将停止工作,因为它无法知道 在哪里 绑定来自您的 HttpServletRequest 的数据您仍然会得到一个FooBar 的实例,但不会将属性设置为请求中的任何值。

    【讨论】:

      【解决方案2】:

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

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

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

      @ModelAttribute 在您的表单包含大量字段时使用。

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

      【讨论】:

        【解决方案3】:

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

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

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

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

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

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

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

        【讨论】:

          【解决方案4】:

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

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

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

          【讨论】:

            【解决方案5】:
            • 在方法级别

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

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

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

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

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

            • 作为方法参数

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

            在用户模型属性后面的代码 sn-p 中填充了来自提交到 addUser 端点的表单的数据。 Spring MVC 在调用提交方法之前在后台执行此操作:

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

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

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

            【讨论】:

            • 这是从 Baeldung 的 Spring MVC 教程中复制粘贴而来的。
            猜你喜欢
            • 2011-11-12
            • 2013-09-09
            • 2020-11-26
            • 1970-01-01
            • 1970-01-01
            • 2015-12-31
            • 2012-09-06
            • 1970-01-01
            • 2017-07-23
            相关资源
            最近更新 更多