1

我正在组合使用 Spring (3.1)、Spring MVC (3.1) 和 Spring Security (3.0),并且我将一个 JSP 页面放在一起,上面有两个表单;一个是登录表格,另一个是注册表格(即创建新用户)。

对于注册表单,我使用 Springform标签,由控制器支持来处理请求,但对于登录表单,我不关心 Springform标签,因为我认为不需要它们。我也不需要编写控制器来处理表单提交,因为只要将请求提交到 Spring Security 就会负责进行身份验证j_spring_security_check

注册表工作正常,但登录表单有问题。似乎当我点击登录表单上的提交按钮时,注册表也被提交了,或者至少 Spring 认为我正在尝试提交该表单。这是JSP:

    <form id="loginform" method="POST" action="<c:url value='j_spring_security_check'/>">
        <label for="existing_email">Email:</label> 
        <input name="j_username" id="existing_email" type="text" value="${SPRING_SECURITY_LAST_USERNAME}" /> 

        <label for="existing_password">Password:</label> 
        <input name="j_password" id="existing_password" type="password" /> 

        <input id="login-form-submit" type="submit" value="Sign in" />
    </form>

    <form:form id="registrationform" modelAttribute="user" method="POST" action="register">
        <form:label path="username" for="email">Email:</form:label> 
        <form:input path="username" name="username" id="email" type="text" /> 
        <form:errors path="username" cssClass="formError" />

        <form:label path="password" for="password">Password:</form:label>
        <form:input path="password" name="password" id="password" type="password" />
        <form:errors path="password" cssClass="formError" />

        <input id="registration-form-submit" type="submit" value="Sign up" />
    </form:form>

请注意,提交类型的输入的form标签不存在,这在我看到的示例中似乎是正常的事情。我想将表单标签添加到提交按钮没有意义,因为它不会映射到目标对象(在本例中为用户)上的任何内容。

当我单击“登录”按钮时,出现以下异常:

SEVERE: Servlet.service() for servlet [appServlet] in context with path [/project1] threw exception [An exception occurred processing JSP page /WEB-INF/views/registration.jsp at line 29
28:         <form:form id="registrationform" modelAttribute="user" method="POST" action="register">
29:             <form:label path="username" for="username">Username:</form:label> 
30:             <form:input path="username" name="username" id="username" type="text" />
31:             <form:errors path="username" cssClass="formError" />
32:              


Stacktrace:] with root cause
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'user' available as request attribute
    at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:141)

我从忘记包含 modelAttribute 属性的情况中认识到这一点form:form,但我当然不想将此表单提交给我的控制器。

我有一种感觉,我犯了一个错误或一个简单的解决方案。任何人都可以推荐一种解决方法或不同的方法吗?

这是在需要时处理注册请求的控制器方法:

    @RequestMapping(value = "**/register", method = RequestMethod.POST)
    public String registerUser(@ModelAttribute("user") @Validated User user, BindingResult errors, ModelMap model) {
        if (errors.hasErrors()) {
            return "registration";
        }
        // Other stuff then...
        return "profile"
    }
4

2 回答 2

1

如果您在表单标记中使用“user”modelAttribute,则必须存在名为“user”的非空请求属性。

在请求属性中添加它的一种方法是您在上面的答案中所做的。其他方式有:

(1) 在 ModelMap 中添加:

    @RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(ModelMap model) {
    model.addAttribute("user", new User());
    model.addAttribute("error", "true");
    return "registration";
}  

(2) 添加请求范围(使用 WebRequest 或 HttpServletRequest):

    @RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(ModelMap model, WebRequest webRequest) {
   webRequest.setAttribute("user", new User(), WebRequest.SCOPE_REQUEST);
    model.addAttribute("error", "true");
    return "registration";
}  

(3) 在方法上使用@ModelAttribute:

    @ModelAttribute("user")
public User user() {
    return new User();
}  

另请参阅在方法上使用 @ModelAttribute和在方法参数上使用 @ModelAttribute

另请注意,您不必使用 type 属性。请参见form:inputform:password

于 2012-05-27T16:59:03.927 回答
0

我认为这个问题特别是当登录失败并且提供相同的页面时,尽管在不同的 URL 路径上,因此通过不同的控制器方法。因此,我最初怀疑问题在于提交的两个表格可能是一个红鲱鱼,尽管我仍然不完全理解发生了什么并且可能与它有关。无论如何,这就是为我解决问题的原因:

我有一个最初看起来像这样的控制器方法:

@RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(ModelMap model) {
    model.addAttribute("error", "true");
    return "registration";
}

在 Spring Security 上下文/loginfailed中,如果登录尝试失败,我将默认指定为要访问的路径。这似乎是需要用户对象的地方,因此如果我按如下方式更改签名,则一切正常:

@RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(@ModelAttribute("user") User user, BindingResult errors, ModelMap model) {
    model.addAttribute("error", "true");
    return "registration";
}

欢迎其他人发表任何评论/澄清。

于 2012-05-27T12:02:26.347 回答