【问题标题】:@ModelAttribute annotation, when to use it?@ModelAttribute 注解,什么时候用?
【发布时间】:2012-01-31 01:38:16
【问题描述】:

假设我们有一个实体 Person、一个控制器 PersonController 和一个 edit.jsp 页面(创建新人员或编辑现有人员)

控制器

@RequestMapping(value = "/edit", method = RequestMethod.POST)
public String editPerson(@RequestParam("fname") String fname, Model model) {
    if(fname == null || fname.length() == 0){
        model.addAttribute("personToEditOrCreate", new Person());
    }
    else{
        Person p = personService.getPersonByFirstName(fname);
        model.addAttribute("personToEditOrCreate", p);
    }

    return "persons/edit";
}

@RequestMapping(value = "/save", method = RequestMethod.POST)
public String savePerson(Person person, BindingResult result) {

    personService.savePerson(person);
    return "redirect:/home";
}

edit.jsp

<form:form method="post" modelAttribute="personToEditOrCreate" action="save">
    <form:hidden path="id"/> 
    <table>
        <tr>
            <td><form:label path="firstName">First Name</form:label></td>
            <td><form:input path="firstName" /></td>
        </tr>
        <tr>
            <td><form:label path="lastName">Last Name</form:label></td>
            <td><form:input path="lastName" /></td>
        </tr>
        <tr>
            <td><form:label path="money">Money</form:label></td>
            <td><form:input path="money" /></td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="Add/Edit Person"/>
            </td>
        </tr>
    </table> 

</form:form>

我正在尝试上面的代码(没有在 savePerson 方法中使用 @ModelAttribute 注释,它工作正常。为什么以及何时需要将注释添加到 person 对象:

@RequestMapping(value = "/save", method = RequestMethod.POST)
public String savePerson(@ModelAttribute("personToEditOrCreate") Person person, BindingResult result) {

    personService.savePerson(person);
    return "redirect:/home";
}

【问题讨论】:

    标签: spring-mvc annotations


    【解决方案1】:

    方法参数上的@ModelAttribute 表示该参数将从模型中检索。如果模型中不存在该参数,则将首先实例化该参数,然后将其添加到模型中。

    【讨论】:

      【解决方案2】:

      你不需要@ModelAttribute参数)只是为了使用一个Bean作为参数

      例如,这些处理程序方法可以很好地处理这些请求:

      @RequestMapping("/a")
      void pathA(SomeBean someBean) {
        assertEquals("neil", someBean.getName());
      }
      
      GET /a?name=neil
      
      @RequestMapping(value="/a", method=RequestMethod.POST)
      void pathAPost(SomeBean someBean) {
        assertEquals("neil", someBean.getName());
      }
      
      POST /a
      name=neil
      

      使用@ModelAttribute方法)在每个请求(例如从数据库中)将默认数据加载到模型中,尤其是在使用@SessionAttributes 时。这可以在ControllerControllerAdvice 中完成:

      @Controller
      @RequestMapping("/foos")
      public class FooController {
      
        @ModelAttribute("foo")
        String getFoo() {
          return "bar";  // set modelMap["foo"] = "bar" on every request
        }
      
      }
      

      FooController转发到的任何JSP:

      ${foo} //=bar
      

      @ControllerAdvice
      public class MyGlobalData {
      
        @ModelAttribute("foo")
        String getFoo() {
          return "bar";  // set modelMap["foo"] = "bar" on every request
        }
      
      }
      

      任何 JSP:

      ${foo} //=bar
      

      如果您想将@ModelAttribute方法)的结果用作默认值,请使用@ModelAttribute参数):

      @ModelAttribute("attrib1")
      SomeBean getSomeBean() {
        return new SomeBean("neil");  // set modelMap["attrib1"] = SomeBean("neil") on every request
      }
      
      @RequestMapping("/a")
      void pathA(@ModelAttribute("attrib1") SomeBean someBean) {
        assertEquals("neil", someBean.getName());
      }
      
      GET /a
      

      使用@ModelAttribute参数)获取存储在flash属性中的对象:

      @RequestMapping("/a")
      String pathA(RedirectAttributes redirectAttributes) {
        redirectAttributes.addFlashAttribute("attrib1", new SomeBean("from flash"));
        return "redirect:/b";
      }
      
      @RequestMapping("/b")
      void pathB(@ModelAttribute("attrib1") SomeBean someBean) {
        assertEquals("from flash", someBean.getName());
      }
      
      GET /a
      

      使用@ModelAttribute参数)获取@SessionAttributes存储的对象

      @Controller
      @SessionAttributes("attrib1")
      public class Controller1 {
      
          @RequestMapping("/a")
          void pathA(Model model) {
              model.addAttribute("attrib1", new SomeBean("neil")); //this ends up in session due to @SessionAttributes on controller
          }
      
          @RequestMapping("/b")
          void pathB(@ModelAttribute("attrib1") SomeBean someBean) {
              assertEquals("neil", someBean.getName());
          }
      }
      
      GET /a
      GET /b
      

      【讨论】:

      • 如何在PUT方法中使用@ModelAttribute
      • 哇。太有用了
      • @ModelAttribute 用作参数时如何设置默认值?例如:(@RequestParam(value = "studentName", defaultValue="Alexa")
      • ModelAttribute 用于获取模型的部分通过 RedirectAttribute 非常有启发性。谢谢
      • 我坦率地认为,@ModelAttribute 是名称最模糊、描述不直观且文档记录最差的注释之一。它给很多人带来了如此多的模棱两可、困惑和头疼……
      【解决方案3】:

      您的问题似乎已经得到解答:

      What is @ModelAttribute in Spring MVC?

      总结答案和博文:当您希望表单支持对象(Person 的实例)在请求之间保持不变时。

      否则,如果没有注释,请求映射方法将假定 Person 是一个新对象,并且绝不会链接到您的表单支持对象。顺便说一句,海报引用的博文真的很棒,绝对是必读的。

      【讨论】:

      • ...但是除非您使用 RedirectAttributesModelMap,否则 Model 中的值不会跨请求持久保存?初始化?
      猜你喜欢
      • 2021-12-09
      • 2010-09-10
      • 2014-02-19
      • 1970-01-01
      • 2011-09-28
      • 1970-01-01
      • 2014-05-04
      相关资源
      最近更新 更多