在阅读了一些教程并从 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) { }
段落中最令人不安的是这行:
"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
以确保所有字段 petId
和 ownerId
都已正确绑定(bind)。
Pet[456,123,XXX]
我们设置 hiddenField
来检查我们的理论并重定向到方法 invokeInternal
,它也需要一个 @ModelAttribute
。如我们所见,第二个方法接收了为第一个方法创建的实例(具有自己的隐藏值)。
关于java - 在 Spring MVC 中创建的模型对象到底在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52126562/