1

我有这堂课:

@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()

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

我的一般问题是:spring beans 是否映射到它们的名称?例如。在这里,我将“用户”作为用户,将“用户”作为会话中的用户,将“密码”作为请求参数,将“密码”作为用户成员变量。

4

1 回答 1

1

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

user1) 您在属性中看到的行为在“在方法参数上使用 @ModelAttribute ”部分进行了解释

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

Spring 是如何做到这一点的?好吧,源代码是最终的答案,但不难猜测:Spring 知道参数是一个实例,User并且通过反射它可以读取类的方法,尤其是它的setters。在这种情况下,它找到setUsername()andsetEmail()并且这些方法的参数是 aString所以它与请求中的参数兼容。

(顺便说一句:@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或等效对象中。例如,您可以在其他Controllers 中使用与方法相同的对象step()

最后只是为了清楚

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

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

于 2012-11-23T05:23:06.777 回答