猿问

在 Spring MVC 中创建的模型对象究竟在哪里?

在阅读了 docs.spring.org 参考中的一些教程和初始文档后,我了解到它是在开发人员创建的 POJO 类的控制器中创建的。但是在阅读本文时,我遇到了以下段落:


一个@ModelAttribute上的方法参数指示参数应该从模型中检索。如果模型中不存在该参数,则应首先实例化该参数,然后将其添加到模型中。一旦出现在模型中,参数的字段应该从具有匹配名称的所有请求参数中填充。这在 Spring MVC 中称为数据绑定,这是一种非常有用的机制,可以使您不必单独解析每个表单字段。


@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)

public String processSubmit(@ModelAttribute Pet pet) {

   

}


在段落中,最令人不安的是这句话:


“如果模型中不存在……”


数据怎么会出现在模型中?(因为我们还没有创建模型 - 它将由我们创建。)


此外,我还看到一些控制器方法接受Model类型作为参数。这意味着什么?它是否Model在某处创建?如果是这样,谁在为我们创造它?


红糖糍粑
浏览 240回答 2
2回答

莫回无

如果模型中不存在该参数,则应首先实例化该参数,然后将其添加到模型中。该段描述了以下代码: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实例,该实例记录在控制器方法调用过程中由HandlerMethodArgumentResolvers 和HandlerMethodReturnValueHandlers做出的与模型和视图相关的决策。新创建的ModelAndViewContainer对象最初填充有flash 属性(如果有):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类:@RestControllerpublic 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 发出 POST 请求/owners/123/pets/456/edit并查看结果: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]一旦出现在模型中,参数的字段应该从具有匹配名称的所有请求参数中填充。我们印了给定的Pet,以确保所有的领域petId,并ownerId已被正确绑定。Pet[456,123,XXX]我们开始hiddenField检查我们的理论并重定向到invokeInternal同样需要@ModelAttribute. 正如我们所见,第二个方法接收了为第一个方法创建的实例(具有自己的隐藏值)。

繁星coding

这证明在我们的控制器/处理程序为特定 URL 调用之前就创建了一个 ModelMap 实例[一个模型对象]&nbsp;public class ModelAndViewContainer {&nbsp; &nbsp; private boolean ignoreDefaultModelOnRedirect = false;&nbsp; &nbsp; @Nullable&nbsp; &nbsp; private Object view;&nbsp; &nbsp; private final ModelMap defaultModel = new BindingAwareModelMap();&nbsp; &nbsp; &nbsp; ....&nbsp; &nbsp; &nbsp; .....&nbsp; &nbsp;}如果我们看到上面的代码片段(取自 spring-webmvc-5.0.8 jar)。BindingAwareModelMap 模型对象很早就创建好了。为了更好地理解为类BindingAwareModelMap添加注释&nbsp; &nbsp;/**&nbsp; &nbsp; &nbsp;* Subclass of {@link org.springframework.ui.ExtendedModelMap} that automatically removes&nbsp; &nbsp; &nbsp;* a {@link org.springframework.validation.BindingResult} object if the corresponding&nbsp; &nbsp; &nbsp;* target attribute gets replaced through regular {@link Map} operations.&nbsp; &nbsp; &nbsp;*&nbsp; &nbsp; &nbsp;* <p>This is the class exposed to handler methods by Spring MVC, typically consumed through&nbsp; &nbsp; &nbsp;* a declaration of the {@link org.springframework.ui.Model} interface. There is no need to&nbsp; &nbsp; &nbsp;* build it within user code; a plain {@link org.springframework.ui.ModelMap} or even a just&nbsp; &nbsp; &nbsp;* a regular {@link Map} with String keys will be good enough to return a user model.&nbsp; &nbsp; &nbsp;*&nbsp; &nbsp; &nbsp;@SuppressWarnings("serial")&nbsp; &nbsp; &nbsp; public class BindingAwareModelMap extends ExtendedModelMap {&nbsp; &nbsp; &nbsp; ....&nbsp; &nbsp; &nbsp; ....&nbsp; &nbsp; &nbsp;}
随时随地看视频慕课网APP

相关分类

Java
我要回答