java - 在 Spring MVC 中创建的模型对象到底在哪里?

标签 java spring spring-mvc modelattribute request-mapping

在阅读了一些教程并从 docs.spring.org 引用资料中阅读了初步文档后,我了解到它是在开发人员创建的 POJO 类的 Controller 中创建的。 但是在阅读本文时,我遇到了以下段落:

An @ModelAttribute on a method argument indicates the argument should be retrieved from the model. If not present in the model, the argument should be instantiated first and then added to the model. Once present in the model, the argument's fields should be populated from all request parameters that have matching names. This is known as data binding in Spring MVC, a very useful mechanism that saves you from having to parse each form field individually.

@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute Pet pet) {
   
}

Spring Documentation

段落中最令人不安的是这行:

"If not present in the model ... "

数据如何存在于模型中? (因为我们还没有创建模型 - 它将由我们创建。)

此外,我还看到一些 Controller 方法接受 Model 类型作为参数。那是什么意思?是否在某处创建了 Model?如果是这样,谁为我们创建了它?

最佳答案

If not present in the model, the argument should be instantiated first and then added to the model.

该段描述了以下一段代码:

if (mavContainer.containsAttribute(name)) {
    attribute = mavContainer.getModel().get(name);
} else {
    // Create attribute instance
    try {
        attribute = createAttribute(name, parameter, binderFactory, webRequest);
    }
    catch (BindException ex) {
        ...
    }
}
...
mavContainer.addAllAttributes(attribute);

(取自 ModelAttributeMethodProcessor#resolveArgument )

对于每个请求,Spring 都会初始化一个 ModelAndViewContainer 实例,该实例记录 HandlerMethodArgumentResolver s 和 HandlerMethodReturnValueHandler s 在调用 Controller 方法期间做出的模型和 View 相关的决策。

新创建的 ModelAndViewContainer 对象最初填充有 flash attributes(如果有):

ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));

这意味着如果参数已经存在于模型中,则不会对其进行初始化。

为了证明这一点,让我们来看一个实际的例子。

Pet 类:

public class Pet {
    private String petId;
    private String ownerId;
    private String hiddenField;

    public Pet() {
         System.out.println("A new Pet instance was created!");
    }

    // setters and toString
}

PetController 类:

@RestController
public class PetController {

    @GetMapping(value = "/internal")
    public void invokeInternal(@ModelAttribute Pet pet) {
        System.out.println(pet);
    }

    @PostMapping(value = "/owners/{ownerId}/pets/{petId}/edit")
    public RedirectView editPet(@ModelAttribute Pet pet, RedirectAttributes attributes) {
        System.out.println(pet);
        pet.setHiddenField("XXX");

        attributes.addFlashAttribute("pet", pet);
        return new RedirectView("/internal");
    }

}

让我们向 URI /owners/123/pets/456/edit 发出 POST 请求并查看结果:

A new Pet instance was created!
Pet[456,123,null]
Pet[456,123,XXX]

A new Pet instance was created!

Spring 创建了一个 ModelAndViewContainer 并且没有找到任何东西来填充实例(这是来自客户端的请求;没有任何重定向)。由于模型是空的,Spring 必须通过调用打印该行的默认构造函数来创建一个新的 Pet 对象。

Pet[456,123,null]

Once present in the model, the argument's fields should be populated from all request parameters that have matching names.

我们打印给定的 Pet 以确保所有字段 petIdownerId 都已正确绑定(bind)。

Pet[456,123,XXX]

我们设置 hiddenField 来检查我们的理论并重定向到方法 invokeInternal ,它也需要一个 @ModelAttribute 。如我们所见,第二个方法接收了为第一个方法创建的实例(具有自己的隐藏值)。

关于java - 在 Spring MVC 中创建的模型对象到底在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52126562/

相关文章:

java - 无法关闭前一帧以查看新帧 java

java - 无法从 HashMap 中删除随机选择的值

java - 使用 Spring Boot 和 MongoDB 的领域事件

java - Spring MVC : Saving a string in servlet-context and accessing from java code

java - 静态内容 - Spring MVC

java - 转换docx后没有空行

java - 构造函数问题,没有找到合适的构造函数

spring - 如何在 Spring Security 3 和 Spring EL 中使用角色层次结构?

java - 如何在 Spring Controller 中读取 JSON 数组值

java - 为什么BindingResult必须跟在@Valid后面呢?