Spring - @ModelAttribute行为

时间:2014-10-24 10:12:33

标签: java spring spring-mvc modelattribute

我遇到了@ModelAttribute使用问题。

有一个简单的Spring(3.2.11)mvc应用程序,具有这样的上下文:

<mvc:annotation-driven />
<context:component-scan base-package="spring.test" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/"></property>
    <property name="suffix" value=".jsp"></property>
</bean> 

有两个DTO:PageDTO和SessionDTO,这两个DTO内部完全相同,只包含一个属性 - 地址和get / set方法。

package spring.test.model;

public class PageDTO implements java.io.Serializable {
    private Address address;
    // getters / setters omitted
}


package spring.test.model;

public class SessionDTO implements java.io.Serializable {
    private Address address;
    // getters / setters omitted
}

package spring.test.model;

public class Address implements java.io.Serializable {
    private String street;
    private String houseNo;
    private String city;
    private String zip;    
    // getters/setters omitted
}

使用一个表单的addressForm.jsp:

<c:url var="actionURL" value="/processForm"/>
<form:form method="POST" modelAttribute="pageDto" action="${actionURL}">
    <form:label path="address.street">Street: </form:label>
    <form:input path="address.street"/>
    <form:label path="address.houseNo">House No: </form:label>
    <form:input path="address.houseNo"/>
    <form:label path="address.city">City: </form:label>
    <form:input path="address.city"/>
    <form:label path="address.zip">ZIP: </form:label>
    <form:input path="address.zip"/>
    <input type="submit" name="searchAddress" value="Submit" />
</form:form>

有一个控制器:

package spring.test.controller;

// imports omitted

@SessionAttributes("sessionDto")
@Controller
public class FormController {

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
    }

    @ModelAttribute("pageDto")
    public PageDTO initPageDTO() {
        return new PageDTO();
    }  

    @ModelAttribute("sessionDto")
    public SessionDTO initSessionDTO() {
        return new SessionDTO();
    }

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ModelAndView renderHome(@ModelAttribute("pageDto") PageDTO pageDto, 
            @ModelAttribute("sessionDto") SessionDTO sessionDto) {       
        return new ModelAndView("addressForm", "pageDto", pageDto);
    }

    @RequestMapping(value = "/processForm", method = RequestMethod.POST)
    public ModelAndView processForm(@ModelAttribute("pageDto") PageDTO pageDto, 
            @ModelAttribute("sessionDto") SessionDTO sessionDto) {
        if(pageDto != null && pageDto.getAddress() != null
                && sessionDto != null && sessionDto.getAddress() != null) {
            System.out.println("pageDto.getAddress().getHouseNo(): " + pageDto.getAddress().getHouseNo());
            System.out.println("sessionDto.getAddress().getHouseNo(): " + sessionDto.getAddress().getHouseNo());
        }
        return new ModelAndView("addressForm", "pageDto", pageDto);
    }

}

这就是问题所在。当我提交地址表时,两个DTO都填写了表格中的数据。我希望只填写jsp中form标签中提到的带有“pageDto”名称的model属性。

来自form-submit事件的日志条目:

[10/24/14 11:23:09:382 CEST] 0000002b SystemOut     O pageDto.getAddress().getHouseNo(): 41
[10/24/14 11:23:09:382 CEST] 0000002b SystemOut     O sessionDto.getAddress().getHouseNo(): 41

当我在控制器中更改processForm方法时,如下所示:

@RequestMapping(value = "/processForm", method = RequestMethod.POST)
public ModelAndView processForm(@ModelAttribute("pageDto") PageDTO pageDto,
        HttpSession httpSession) {
    SessionDTO sessionDto = (SessionDTO) httpSession.getAttribute("sessionDto");
    if(pageDto != null && pageDto.getAddress() != null
            && sessionDto != null && sessionDto.getAddress() != null) {
        System.out.println("pageDto.getAddress().getHouseNo(): " + pageDto.getAddress().getHouseNo());
        System.out.println("sessionDto.getAddress().getHouseNo(): " + sessionDto.getAddress().getHouseNo());
    }
    return new ModelAndView("addressForm", "pageDto", pageDto);
}

...它按预期工作 - sessionDto未填入表单中的数据,因此日志中不会出现任何条目(sessionDto.getAddress()== null)。

拥有2个DTO的动机,一个存储在会话中:

  • 并非所有模型的属性都显示在表单上,​​所以我必须使用input type = hidden而不是松散数据
  • 我需要能够在提交表单
  • 时找出用户更改了哪些属性

任何想法都赞赏!

1 个答案:

答案 0 :(得分:1)

在提交时,ModelAttribute的名称主要有美容效果。请求参数包含在 hash 中,其中keys是先前响应(*)发送的<form:input>元素的路径,值来自表单中键入的用户。但是请求中modelAttribute的名称不是,而Spring无法猜测它。

它接受方法的所有@ModelAttribute参数,并尝试设置与请求参数的对应的属性,并在完成后将它们放入使用您提供的名称{/ 1}}

因此,该名称仅用于准备响应,而不用于解析请求。

(*)如果请求来自提交表单,但它可以通过任何其他方式生成 - 只需Spring MVC期望遵循该约定的请求参数