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";
}
我最近开始在 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";
}