春季MVC 3中的表格提交 - 说明

2022-09-01 10:52:14

我在理解Spring 3 MVC中的表单提交如何工作时遇到问题。

我想做的是创建一个控制器,它将获取用户名并将其显示给他。不知何故,我做到了,但我真的不明白它是如何工作的。所以。。

我有一个表单,看起来像这样:

<form:form method="post" modelAttribute="person">
    <form:label path="firstName">First name</form:label>
    <form:input path="firstName" />
    <br />

    <form:label path="lastName">Last name</form:label>
    <form:input path="lastName" />
    <br />

    <input type="submit" value="Submit" />
</form:form>

我还有一个控制器,看起来像这样:

@Controller
public class HomeController {

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String showHelloPage(Model model) {
        model.addAttribute("person", new Person());
        return "home";
    }

    @RequestMapping(value = "/", method = RequestMethod.POST)
    public String sayHello(Person person, Model model) {
        model.addAttribute("person", person);
        return "home";
    }
}

要向用户显示欢迎消息,我在 JSP 页中使用以下代码:

<c:if test="${not empty person.firstName and not empty person.lastName}">
    Hello ${person.firstName} ${person.lastName}!
</c:if>

它可以工作(我省略了XML配置文件,因为它们与问题无关)。

我认为表单中的“modelAttribute”属性指向bean变量,该变量应该用输入的值填充(如其“路径”属性中设置的那样)。但看起来,它以一种非常不同的方式工作。如果我删除该行

model.addAttribute("person", new Person());

从“showHelloPage”方法中,我得到了一个(常见的)例外“既不绑定结果也不...”。

此外,在开始时,“sayHello”方法看起来像这样:

(...)
public String sayHello(@ModelAttribute("person") Person person, Model model) {
(...)

我的意思是,它有“ModelAttribute”注释。我添加了它,因为在我读过的教程中,它总是存在。但是在我删除它之后,一切都很顺利,就像以前一样。

所以我的问题是 - “ModelAttribute”非自然化有什么用?在表单中省略“modelAttribute”属性是否有某种方法?第二部分,是什么方法(也许是一些注释)使表单自动将输入的值绑定到适当的bean属性(这将被声明为方法参数)?在发送表单之前无需添加空bean(因为我现在必须这样做)。

感谢您的回复(这不是指向Spring文档的链接,因为我已经阅读了它)。


答案 1

在这种情况下,@ModelAttribute注释用于标识Spring应添加为模型属性的对象。模型属性是从属性抽象出来的。基本上,它们是由一些键标识的对象,这些键将进入属性。为此,可以手动添加带有 、的带注释方法的属性,或者使用 添加注释的方法参数。HttpServletRequestHttpServletRequestModel#addAttribute(String, Object)@ModelAttribute@ModelAttribute

您需要了解的是Spring如何解析处理程序方法参数并注入参数。它使用 HandlerMethodArgumentResolver 接口来执行此操作。有许多实现类(参见javadoc),每个类都有责任通过反射将Spring将使用的参数返回给你的处理程序方法。仅当该方法返回特定参数时,Spring 才会调用该方法。resolveArgument()invoke()resolveArgument()HandlerMethodArgumentResolversupportsParameter()true

这里讨论的实现是ServletModelAttributeMethodProcessor,它从ModelAttributeMethodProcessor扩展而来,它指出HandlerMethodArgumentResolver

解析使用 @ModelAttribute 批注的方法参数,并处理使用 @ModelAttribute 批注的方法的返回值。

春天(3.2)将注册这个和其他HandlerMethodArgumentResolver

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();

    // Annotation-based argument resolution
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
    resolvers.add(new RequestParamMapMethodArgumentResolver());
    resolvers.add(new PathVariableMethodArgumentResolver());
    resolvers.add(new ServletModelAttributeMethodProcessor(false));
    resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));
    resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));
    resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new RequestHeaderMapMethodArgumentResolver());
    resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));

    // Type-based argument resolution
    resolvers.add(new ServletRequestMethodArgumentResolver());
    resolvers.add(new ServletResponseMethodArgumentResolver());
    resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
    resolvers.add(new RedirectAttributesMethodArgumentResolver());
    resolvers.add(new ModelMethodProcessor());
    resolvers.add(new MapMethodProcessor());
    resolvers.add(new ErrorsMethodArgumentResolver());
    resolvers.add(new SessionStatusMethodArgumentResolver());
    resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

    // Custom arguments
    if (getCustomArgumentResolvers() != null) {
        resolvers.addAll(getCustomArgumentResolvers());
    }

    // Catch-all
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
    resolvers.add(new ServletModelAttributeMethodProcessor(true));

    return resolvers;
}

当Spring需要调用您的处理程序方法时,它将循环访问参数类型和上面的列表,并使用第一个.supportsParameter()

请注意,添加了两个实例(一个在注释之后)。有一个字段,告诉它是否应该查找。第一个实例必须查找 ,第二个实例不查找。Spring这样做是为了让你注册自己的实例,请参阅注释。ServletModelAttributeMethodProcessor//catch allModelAttributeMethodProcessorannotationNotRequired@ModelAttribute@ModelAttributeHandlerMethodArgumentResolver// Custom arguments


具体说来

@RequestMapping(value = "/", method = RequestMethod.POST)
public String sayHello(Person person, Model model) {
    model.addAttribute("person", person);
    return "home";
}

在这种情况下,参数是否带注释并不重要。A将解析它并绑定表单字段,即。请求参数,到实例的字段。您甚至不需要将其添加到 中,因为该类将处理它。PersonModelAttributeMethodProcessormodelModelAttributeMethodProcessor

在您的方法中showHelloPage()

model.addAttribute("person", new Person());

与 taglib 一起需要。这就是它解析其字段的方式。<form>input


所以我的问题是 - “ModelAttribute”非自然化有什么用?

自动将指定的参数(或方法返回值)添加到模型中。

在表单中省略“modelAttribute”属性是否有某种方法?

否,绑定在 中查找对象并将其字段绑定到 html 元素。formModelinput

第二部分,是什么方法(也许是一些注释)使表单自动将输入的值绑定到适当的bean属性(这将被声明为方法参数)?在发送表单之前无需添加空bean(因为我现在必须这样做)。

Spring 标记锁定到模型属性对象上,并使用其字段来创建和元素。无论对象最终如何出现在模型中,只要它确实如此,它就无关紧要。如果它找不到具有您指定的名称(键)的模型属性,它将引发异常,如您所见。<form>inputlabel

 <form:form method="post" modelAttribute="person">

提供空bean的替代方法是自己创建html。Spring所做的就是使用bean的字段名称来创建一个元素。所以这个<form>input

<form:form method="post" modelAttribute="person">
    <form:label path="firstName">First name</form:label>
    <form:input path="firstName" />

创建类似的东西

<form method="post" action="[some action url]">
    <label for="firstName">First name<label>
    <input type="text" name="firstName" value="[whatever value firstName field had]" />
    ...

Spring 使用该属性将请求参数绑定到实例字段。name


答案 2

推荐