解释此Spring MVC Controller行为
问题内容:
我有这个课:
@Component
@Scope("session")
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue
@GenericGenerator(name = "incremental", strategy = "increment")
private Long userID;
@Column(nullable = false)
private String username;
@Column(nullable = false)
private String email;
@Column(nullable = false)
private String password;
// getters and setters
}
而这个控制器:
@Controller
@SessionAttributes("user")
@Scope("request")
public class UserCreationWizard {
@Autowired
private User user;
@ModelAttribute("user")
private User createUser() {
return user;
}
@RequestMapping(value = "/new/users/page/", method = RequestMethod.GET)
public String begin(HttpServletRequest request) {
return "wizard";
}
@RequestMapping(value = "/new/users/page/{page}", method = RequestMethod.POST)
public String step(@ModelAttribute("user") User user,
@RequestParam("username") String username,
@RequestParam("email") String password,
@PathVariable() Integer page) {
return "wizard" + page;
}
@RequestMapping(value = "/new/users/page/end", params = "submit", method = RequestMethod.POST)
public String end(@RequestParam("password") String password) {
user.setPassword(password);
user.setActive(true);
user.setLastLoggedIn(Calendar.getInstance());
Session s = HibernateUtils.getSessionFactory().openSession();
Transaction t = s.beginTransaction();
try {
s.persist(user);
s.flush();
t.commit();
s.close();
} catch (HibernateException e) {
t.rollback();
}
return "wizard";
}
}
begin()
只需在用户创建向导中加载第一个视图(jsp)。它有输入字段username
和email
。在视图中,您将触发POST表单提交step()
。在第二个视图(wizard
+ page.jsp)中,您有一个password
字段和一个触发了的输入end()
。
- 在调试模式下,我注意到在中
step()
,我已将User作为ModelAttribute传递给我,不需要为用户名和密码设置其字段。它们是从RequestParams属性中自动获取的。在end()
然而,在我没有的ModelAttribute,我不得不手动设置密码。Spring如何管理这个? - 另外,如果我
createUser()
在Controller中删除该方法,则应用程序将失败,无法找到“用户”的会话属性。该方法如何作为方法参数链接到MethodAttribute? - 最后,如果我删除@SessionAttributes,应用程序不会失败,但是我感觉出了点问题。用户用户现在对所有httprequest是全局的吗?
我的一般问题是:春豆是否映射到其名称?例如。在这里,我以“ user”作为用户,在会话中具有“ user”,“
password”作为requestparam,“ password”作为User成员变量。
问题答案:
好,很多问题。让我们看看,所有引用都是针对当前Spring MVC版本的文档。
1)在你看到的行为user
属性的部分解释说,“
在一个方法参数使用@ModelAttribute ”
方法参数上的@ModelAttribute指示应从模型中检索参数。如果模型中不存在该参数,则应首先实例化该参数,然后将其添加到模型中。一旦出现在模型中,则应从具有匹配名称的所有请求参数中填充参数的字段。这在Spring
MVC中称为数据绑定,这是一种非常有用的机制,使您不必分别解析每个表单字段。
Spring如何做到这一点?好吧,源代码是最终的答案,但要猜测起来并不难:Spring知道参数是的实例,User
并且通过反射它可以读取类的方法,特别是其
setter
。在这种情况下,它找到setUsername()
和setEmail()
,这些方法的参数是a,String
因此它与请求中的参数兼容。
(顺便说一句:@RequestParam("email") String password
可能是一个错误。至少是令人困惑的)
2)该方法createUser()
之前带有注释@ModelAttribute("user")
。这将在“
在方法上使用@ModelAttribute ”部分介绍
方法上的@ModelAttribute指示该方法的目的是添加一个或多个模型属性。
因此,此方法将与名称相关联的对象"user"
放在模型上,然后可供其他方法用作参数,例如step()
。注意,注释控制着模型中对象使用的标识符。如果将代码更改为
@ModelAttribute("strangeWeirdIdentifier")
private User createUser() { return user; }
该应用程序将中断。但是,如果将step()
签名更改为
public String step(@ModelAttribute("strangeWeirdIdentifier") User user,
@RequestParam("username") String username,
@RequestParam("email") String password,
@PathVariable() Integer page) {
3)1)和2)中描述的过程在请求期间将对象存储在模型中。使用类注释,@SessionAttributes("user")
您可以延长对象的寿命,将其添加到当前对象Session
或等效对象中。例如,您可以在其他Controller
s中使用与step()
方法相同的对象。
最后只是要清楚
- 在问题2中看到的注释发生在问题1中出现的用法之前。
- 您可能不需要问题3的注释
- Spring不会将bean映射到Java代码中的名称,而是映射到注释中使用的名称。为了清楚起见,重复与示例中相同的名称并不罕见。
希望这比官方文档更清楚,通常太简短了,我给你。