Spring MVC and the @ModelAttribute Annotation – Spring MVC和@ModelAttribute注解

最后修改: 2016年 6月 27日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

One of the most important Spring MVC annotations is the @ModelAttribute annotation.

最重要的Spring MVC注解之一是@ModelAttribute注解。

@ModelAttribute is an annotation that binds a method parameter or method return value to a named model attribute, and then exposes it to a web view.

@ModelAttribute是一个注解,它将一个方法参数或方法返回值绑定到一个命名的模型属性上,然后将其暴露给一个Web视图。

In this tutorial, we’ll demonstrate the usability and functionality of this annotation through a common concept, a form submitted from a company’s employee.

在本教程中,我们将通过一个常见的概念,即一个公司员工提交的表格,来展示这个注释的可用性和功能。

2. @ModelAttribute in Depth

2.@ModelAttribute深入浅出

As the introductory paragraph revealed, we can use @ModelAttribute either as a method parameter or at the method level.

正如介绍性段落所揭示的,我们可以将@ModelAttribute作为方法参数或在方法级别使用。

2.1. At the Method Level

2.1.在方法层面

When we use the annotation at the method level, it indicates the purpose of the method is to add one or more model attributes. Such methods support the same argument types as @RequestMapping methods, but they can’t be mapped directly to requests.

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

Let’s look at a quick example here to understand how this works:

让我们在这里看一个快速的例子,以了解这一点是如何运作的。

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

In the above example, we see a method that adds an attribute named msg to all models defined in the controller class.

在上面的例子中,我们看到一个方法为所有在控制器类中定义的model添加一个名为msg的属性。

Of course, we’ll see this in action later in the article.

当然,我们将在文章的后面看到这一点的行动。

In general, Spring MVC will always make a call to that method first, before it calls any request handler methods. Basically, @ModelAttribute methods are invoked before the controller methods annotated with @RequestMapping are invoked. This is because the model object has to be created before any processing starts inside the controller methods.

一般来说,Spring MVC总是先调用该方法,然后再调用任何请求处理方法。基本上,@ModelAttribute方法会在@RequestMapping注释的控制器方法被调用之前被调用。这是因为模型对象必须在控制器方法的任何处理开始之前被创建。

It’s also important that we annotate the respective class as @ControllerAdvice. Thus, we can add values in Model that’ll be identified as global. This actually means that for every request, a default value exists for every method in the response.

同样重要的是,我们将相应的类注释为@ControllerAdvice。因此,我们可以在Model中添加将被识别为全局的值。这实际上意味着,对于每个请求,响应中的每个方法都存在一个默认值。

2.2. As a Method Argument

2.2.作为一个方法论证

When we use the annotation as a method argument, it indicates to retrieve the argument from the model. When the annotation isn’t present, it should first be instantiated, and then added to the model. Once present in the model, the arguments fields should populate from all request parameters that have matching names.

当我们使用注解作为方法参数时,它表示要从模型中获取参数。当注解不存在时,它应该首先被实例化,然后被添加到模型中。一旦出现在模型中,参数字段应该从所有具有匹配名称的请求参数中填充。

In the following code snippet, we’ll populate the employee model attribute with data from a form submitted to the addEmployee endpoint. Spring MVC does this behind the scenes before invoking the submit method:

在下面的代码片段中,我们将用提交给addEmployee端点的表单数据来填充employee模型属性。在调用提交方法之前,Spring MVC会在幕后完成这项工作。

@RequestMapping(value = "/addEmployee", method = RequestMethod.POST)
public String submit(@ModelAttribute("employee") Employee employee) {
    // Code that uses the employee object

    return "employeeView";
}

Later in this article, we’ll see a complete example of how to use the employee object to populate the employeeView template.

在本文后面,我们将看到一个完整的例子,说明如何使用employee对象来填充employeeView模板。

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注释的自定义类参数。

In Spring MVC, we refer to this as data binding, a common mechanism that saves us from having to parse each form field individually.

在Spring MVC中,我们把这称为数据绑定,这是一种常见的机制,它使我们不必单独解析每个表单字段。

3. Form Example

3.表格范例

In this section, we’ll look at the example outlined in the overview section, a very basic form that prompts a user (specifically a company employee) to enter some personal information (specifically name and id). After the submission is complete, and without any errors, the user expects to see the previously submitted data displayed on another screen.

在本节中,我们将查看概述部分所概述的示例,这是一个非常基本的表单,它提示用户(特别是公司员工)输入一些个人信息(特别是姓名id)。提交完成后,如果没有任何错误,用户希望看到先前提交的数据显示在另一个屏幕上。

3.1. The View

3.1.观点

Let’s first create a simple form with id and name fields:

让我们首先创建一个带有id和name字段的简单表单。

<form:form method="POST" action="/spring-mvc-basics/addEmployee" 
  modelAttribute="employee">
    <form:label path="name">Name</form:label>
    <form:input path="name" />
    
    <form:label path="id">Id</form:label>
    <form:input path="id" />
    
    <input type="submit" value="Submit" />
</form:form>

3.2. The Controller

3.2.控制器

Here’s the controller class, where we’ll implement the logic for the aforementioned view:

这里是控制器类,我们将在这里实现上述视图的逻辑。

@Controller
@ControllerAdvice
public class EmployeeController {

    private Map<Long, Employee> employeeMap = new HashMap<>();

    @RequestMapping(value = "/addEmployee", method = RequestMethod.POST)
    public String submit(
      @ModelAttribute("employee") Employee employee,
      BindingResult result, ModelMap model) {
        if (result.hasErrors()) {
            return "error";
        }
        model.addAttribute("name", employee.getName());
        model.addAttribute("id", employee.getId());

        employeeMap.put(employee.getId(), employee);

        return "employeeView";
    }

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

In the submit() method, we have an Employee object bound to our View. We can map our form fields to an object model as simply as that. In the method, we’re fetching values from the form and setting them to ModelMap.

submit()方法中,我们有一个Employee对象与我们的View绑定。我们可以简单地将我们的表单字段映射到一个对象模型上。在该方法中,我们从表单中获取值并将它们设置为ModelMap

In the end, we return employeeView, which means that we call the respective JSP file as a View representative.

最后,我们返回employeeView,这意味着我们作为View代表调用了相应的JSP文件。

Furthermore, there’s also an addAttributes() method. Its purpose is to add values in the Model that’ll be identified globally. That is, every request to every controller method will return a default value as a response. We also have to annotate the specific class as @ControllerAdvice.

此外,还有一个addAttributes()方法。它的目的是在Model中添加值,这些值将被全球识别。也就是说,每个控制器方法的请求都将返回一个默认值作为响应。我们还必须将这个特定的类注释为@ControllerAdvice.

3.3. The Model

3.3.该模型

As previously mentioned, the Model object is very simple and contains all that the “front-end” attributes require. Now let’s have a look at an example:

如前所述,Model对象非常简单,包含 “前端 “属性所需的全部内容。现在让我们看一下一个例子。

@XmlRootElement
public class Employee {

    private long id;
    private String name;

    public Employee(long id, String name) {
        this.id = id;
        this.name = name;
    }

    // standard getters and setters removed
}

3.4. Wrap Up

3.4 总结

@ControllerAdvice assists a controller, and in particular, @ModelAttribute methods that apply to all @RequestMapping methods. Of course, our addAttributes() method will be the very first to run, prior to the rest of the @RequestMapping methods.

@ControllerAdvice协助控制器,特别是@ModelAttribute方法,适用于所有@RequestMapping方法。当然,我们的addAttributes()方法将是第一个运行的,在其他@RequestMapping方法之前。

Keeping that in mind, and after both submit() and addAttributes() are run, we can refer to them in the View returned from the Controller class by mentioning their given name inside a dollarized curly-braces duo, like ${name}.

记住这一点,在submit()addAttributes()运行后,我们可以在Controller类返回的View中引用它们,在美元化的大括号中提到它们的名字,比如${name}

3.5. Results View

3.5.结果查看

Now let’s print what we received from the form:

现在让我们打印我们从表格中收到的内容。

<h3>${msg}</h3>
Name : ${name}
ID : ${id}

4. Conclusion

4.结论

In this article, we investigated the use of the @ModelAttribute annotation for both method arguments and method level use cases.

在这篇文章中,我们调查了@ModelAttribute注解在方法参数和方法级别用例中的使用情况

The implementation of this article can be found in the github project.

本文的实现可以在github项目中找到。