解释这个Spring MVC Controller的行为 [英] Explain this Spring MVC Controller behavior

查看:138
本文介绍了解释这个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)。它有用户名电子邮件的输入字段。在视图中,您进行POST表单提交,触发 step()。在第二个视图(向导+ page.jsp)中,您有一个密码字段和一个触发 end()

begin() just loads the first view (a jsp) in the user creation wizard. It has input fields for username and email. In the view, you make a POST form submission which triggers step(). In the second view (wizard+page.jsp), you have a password field and a submit input that triggers end().


  1. 在调试模式下,我注意到在 step()中,其中我已将User作为
    a ModelAttribute传递给我,我不需要为username和
    密码设置其字段。它们会自动从RequestParams
    属性中获取。在 end()但是,如果我没有ModelAttribute,
    我必须手动设置密码。 Spring如何管理这个?

  2. 如果我在Controller中取出 createUser()方法,
    应用程序无法说它找不到
    user的会话属性。如何将此方法作为方法
    参数链接到MethodAttribute?

  3. 最后,如果我取出@SessionAttributes,应用程序不会失败,但我觉得有些事情出错了。用户用户现在是否对所有httprequests都是全局的?

  1. In debug mode I noticed that in step(), where I've passed User as a ModelAttribute, I don't need to set its fields for username and password. They are automatically grabbed from the RequestParams attributes. In end() however, where I don't have a ModelAttribute, I have to set the password manually. How does Spring manage this?
  2. Also if I take out the createUser() method in the Controller, the application fails saying it couldn't find a session attribute for "user". How is this method linked to MethodAttribute as a method parameter?
  3. Lastly, if I take out @SessionAttributes, the application doesn't fail but I feel like something is going wrong. Will the User user now be global to all httprequests?

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

My general question is: are spring beans mapped to their name? Eg. Here I have 'user' as a user and 'user' in the session, 'password' as a requestparam and 'password' as the User member variable.

推荐答案

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

Ok, many questions. Let's see, all references are to the documentation for the current Spring MVC version.

1)您在用户属性在在方法参数上使用@ModelAttribute


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

An @ModelAttribute on a method argument indicates the argument should be retrieved from the model. If not present in the model, the argument should be instantiated first and then added to the model. Once present in the model, the argument's fields should be populated from all request parameters that have matching names. This is known as data binding in Spring MVC, a very useful mechanism that saves you from having to parse each form field individually.

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

How does Spring does this? Well, the source code is the ultimate answer but it's not that hard to make a guess: Spring knows the argument is an instance of User and via reflection it can read the methods of the class, particularly its setters. In this case it finds setUsername() and setEmail() and the argument for those methods is a String so it's compatible with the parameters from the request.

(BTW: @RequestParam(email) )字符串密码可能是一个错误。至少令人困惑)

(BTW: @RequestParam("email") String password is possibly a mistake. At the very least is confusing)

2)方法 createUser() 前面是注释 @ModelAttribute(user)。这包含在在方法上使用@ModelAttribute

2) The method createUser() is preceded by the annotation @ModelAttribute("user"). This is covered by the section "Using @ModelAttribute on a method"


方法上的@ModelAttribute表示该方法的用途是
添加一个或多个模型属性。

An @ModelAttribute on a method indicates the purpose of that method is to add one or more model attributes.

因此,此方法会放置一个与名称相关联的对象模型上的user,然后可以通过其他方法用作参数,例如 step()。请注意,注释控制模型中对象使用的标识符。如果您将代码更改为

Therefore, this method puts an object associated with the name "user" on the model and is then available to be used as a parameter by other methods, like step(). Notice that the annotation controls the identifier used by the object in the model. If you change the code to

@ModelAttribute("strangeWeirdIdentifier")
private User createUser() { return user; }

应用程序将中断。但如果您将 step()签名更改为

the app will break. But it will work again if you change the step() signature to

public String step(@ModelAttribute("strangeWeirdIdentifier") User user,
                   @RequestParam("username") String username,
                   @RequestParam("email") String password,
                   @PathVariable() Integer page) {

3)1)和2)中描述的过程将对象存储在模型中在请求期间。使用类注释 @SessionAttributes(user),您可以延长对象的生命周期,将其添加到当前会话或类似的东西。例如,您可以使用其他 Controller 中的对象,与 step()方法相同。

3) The process described in 1) and 2) stores objects in the model during a request. With the class annotation @SessionAttributes("user") you extend the life of the object adding it to the current Session or something equivalent. By example you could then use the object in other Controllers in the same was as the step() method.

最后要清楚


  • 问题2中的注释发生在之前您在问题1中看到的用法。

  • 可能不需要问题3中的注释

  • Spring不会将bean映射到Java中的名称代码,但注释中使用的名称。为了清楚起见,在您的示例中重复使用相同的名称并不罕见。

希望这比设置更明确官方文档,通常太简短,我会给你。

Hope this manages to be more clear than the official documentation whch, is usually too brief, I'll give you that.

这篇关于解释这个Spring MVC Controller的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆