Spring 框架 JSP 表单处理:@ModelAttribute

Spring Framework JSP Form Handling: @ModelAttribute

我最近开始在 Spring 框架中使用 JSP,并尝试实现一个表单处理页面。

我创建了一个接受用户输入的基本表单页面,在他们点击提交后,他们会收到一个确认页面,其中包含他们输入的内容。

这是我控制器中的两个映射方法class:

import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.redcup.model.Person;
import com.redcup.model.User;
import com.redcup.test.ServletTestBean;

import javax.annotation.PostConstruct;

@Controller
public class RedCupController {

    private final Logger logger = LoggerFactory.getLogger(RedCupController.class);

    @PostConstruct
    public void intializeComplete() { 
        logger.info("Controller initialized");
    }

    @RequestMapping(method=RequestMethod.GET, value="/health")
    @ResponseBody
    public String getHealth()
    {
        logger.info("GET /health invoked.");

        return "hello world!";
    }

    @RequestMapping(method=RequestMethod.GET, value="/welcome")
    public String getWelcome(Model model) { 
        User user = new User();
        model.addAttribute("userform", user);
        return "welcome"; 
    }

    @RequestMapping(method=RequestMethod.POST, value="/confirmation")
    public String getConfirmation(@ModelAttribute("userform") User user, @ModelAttribute("pew") User user2, 
                                @ModelAttribute("whomp")Person person, Model model) {

        user = getUserForm();
        user2 = getUserForm2();

        System.out.println("hello: " + user);
        System.out.println("goodbye: " + user2);

        System.out.println("user: " + user.getFirstName());
        System.out.println("user: " + user.getLastName());
        System.out.println("user: " + user.getEmail());
        System.out.println("user: " + user.getAge());

        System.out.println("user2: " + user2.getFirstName());
        System.out.println("user2: " + user2.getLastName());
        System.out.println("user2: " + user2.getEmail());
        System.out.println("user2: " + user2.getAge());

        System.out.println("person: " + person.getName());
        System.out.println("person: " + person.getNum2());

        model.addAttribute("user", user);
        model.addAttribute("user2", user2);
        model.addAttribute("person", person);

        return "confirmation";
    }

    @ModelAttribute("userform")
    public User getUserForm() {
        return new User();
    }

    @ModelAttribute("userform2") 
    public User getUserForm2() { 
        return new User();
    }
}

模型的用户 class:

public class 用户 {

private String firstName;
private String lastName;
private String email;
private int age; 

public User() { 
    firstName = "John";
    lastName =  "Smith";
    email = "default email";
    age = 1; 
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getFirstName () { 
    return firstName;
}

public void setLastName(String lastName) { 
    this.lastName = lastName;
}

public String getLastName() { 
    return lastName;
}

public void setEmail(String email) { 
    this.email = email;
}

public String getEmail() { 
    return email;
}

public void setAge (int age) {
    this.age = age;
}

public int getAge() { 
    return age;
}

}

下面是表单输入页面welcome.jsp:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
    <div align="center">

        <form:form action="confirmation" method="post" commandName="userform">
            <form:input path="firstName"/>
            <form:input path="lastName"/>
            <form:input path="email"/>
            <form:input path="age"/>
            <input type="submit" value="Press this to submit"/>
        </form:form>
    </div>
</body>
</html>

在我的控制器处理程序中:getConfirmation 我有两个用户参数(user 和 user2)。我感到困惑的部分是,当我在 welcome.jsp 中单击提交时,user 和 user2 填充了相同的参数welcome.jsp 中模型的确切值。我不确定为什么会发生这种情况,因为我认为 @ModelAttribute 只会将相应的模型属性分配给指定的参数(即用户将在 commandName 用户表单下接收模型)。

但对我来说,@ModelAttribute 注释似乎没有做任何事情。当@ModelAttributes 具有不同的键(即 userform 与 userform2)并且当我什至删除 @ModelAttribute 注释时,user 和 user2 参数将使用相同的字段值(我在表单中输入的内容)填充,user 和 user2 仍将是用相同的字段值填充。

有人可以解释为什么会发生这种情况以及 @ModelAttribute 注释到底做了什么?

提前致谢!

编辑

我根据 Alan 的 Hay 的建议创建了一个 UserWrapper class:

public class UserWrapper {

    private User user1;
    private User user2; 

    public User getUser1() { 
        return user1;
    }

    public User getUser2() { 
        return user2; 
    }

    public void setUser1(User user) { 
        user1 = user;
    }

    public void setUser2(User user) { 
        user2 = user;
    }

    public void setUser1FirstName(String firstName) {
        user1.setFirstName(firstName);
    }

    public String getUser1FirstName() { 
        return user1.getFirstName();
    }

    public void setUser2FirstName(String firstName) {
        user2.setFirstName(firstName);
    }

    public String getUser2FirstName() { 
        return user2.getFirstName();
    }
}

并使用以下表格更新了我的 welcome.jsp:

    <form:form action="confirmation" method="post" commandName="userform">
        <form:input path="user1.firstName"/>
        <form:input path="user1.lastName"/>
        <form:input path="user1.email"/>
        <form:input path="user1.age"/>
        <input type="submit" value="Press this to submit"/>
    </form:form>

这是预期的行为。

这里要注意的重要一点是,如果您查看生成的 HTML 编辑页面,您会看到它有如下输入:

<input name="firstName"  type="text" value="user">
<input name="lastName"  type="text" value="7702">

即。 没有明确将其绑定到模型对象的任何特定实例。现在,在提交表单时,Spring 处理程序将查看您在处理程序方法中指定为模型属性的内容,并将尝试将提交的参数绑定到这些模型对象中的匹配字段,而不管限定符 - 这就是你看。

要获得您期望的行为,您需要像下面这样包装两个模型属性:

创建包装器作为表单支持对象:

public class UserWrapper(){

    private User user1;
    private User user2;

    public User getUser1(){
        return user1;
    }

    public User getUser2(){
        return user2;
    }
}

专门将表单字段仅绑定到 User1

<form:form action="confirmation" method="post" commandName="userWrapper">
    <form:input path="user1.firstName"/>
    <form:input path="user1.lastName"/>
    <form:input path="user1.email"/>
    <form:input path="user1.age"/>
    <input type="submit" value="Press this to submit"/>
</form:form>

更新处理程序:

@RequestMapping(method=RequestMethod.POST, value="/confirmation")
public String getConfirmation(@ModelAttribute UserWrapper wrapper) {

    System.out.println("user: " + wrapper.getUser1().getFirstName());
    System.out.println("user: " + wrapper.getUser2().getFirstName());

    return "confirmation";
}