解释这个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)。 它有用usernameemail输入字段。 在视图中,您进行POST表单提交,触发step() 。 在第二个视图(向导+ page.jsp)中,您有一个password字段和一个触发end()的提交输入。

  1. 在调试模式中,我注意到在step() ,我将User作为ModelAttribute传递,我不需要为用户名和密码设置其字段。 它们会自动从RequestParams属性中获取。 但是在end()中,我没有ModelAttribute,我必须手动设置密码。 Spring如何管理这个?
  2. 此外,如果我在Controller中取出createUser()方法,应用程序将失败,说它无法找到“user”的会话属性。 该方法如何作为方法参数链接到MethodAttribute?
  3. 最后,如果我拿出@SessionAttributes,应用程序不会失败,但我觉得有些事情出错了。 用户用户现在是否对所有httprequests都是全局的?

我的一般问题是:春豆是否映射到他们的名字? 例如。 在这里,我在会话中将’user’作为用户和’user’,将password作为requestparam,将’password’作为User成员变量。

好的,很多问题。 让我们看看,所有引用都是针对当前Spring MVC版本的文档。

1)您在user属性中看到的行为在“ 在方法参数上使用@ModelAttribute”一节中进行了解释

方法参数上的@ModelAttribute指示应从模型中检索参数。 如果模型中不存在,则应首先实例化参数,然后将其添加到模型中。 一旦出现在模型中,参数的字段应该从具有匹配名称的所有请求参数中填充。 这在Spring MVC中称为数据绑定,这是一种非常有用的机制,可以使您不必单独解析每个表单字段。

Spring如何做到这一点? 好吧,源代码是最终的答案,但并不难猜测:Spring知道参数是User一个实例,通过reflection它可以读取类的方法,特别是它的setter 。 在这种情况下,它找到setUsername()setEmail() ,这些方法的参数是一个String因此它与请求中的参数兼容。

(BTW: @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或等效的Session 。 通过示例,您可以在其他Controller中使用与step()方法相同的对象。

最后只是为了清楚

  • 问题2中的注释发生在问题1中的用法之前。
  • 可能不需要问题3中的注释
  • Spring不会将bean映射到Java代码中的名称,而是映射到注释中使用的名称。 为了清楚起见,重复与示例中相同的名称并不罕见。

希望这比官方文档更清晰,通常太简短,我会给你的。