Spring验证:Null ModelAndView返回DispatcherServlet

时间:2015-08-07 19:53:09

标签: spring validation model-view-controller model

我很确定以前没有在这里描述过这个问题。我也很确定这是我的一个愚蠢的错误。

问题简述:

  • 我创建了一个用户登录表单。
  • 当用户登录信息是 无论是在服务层更正还是失败,一切正常
  • 当用户 输入验证失败,我从spring获得以下消息: " Null ModelAndView返回带有名称的DispatcherServlet ' AssessmentAdmin':假设HandlerAdapter已完成请求 处理"
  • 然后我在网页上收到400错误:"请求发送的请求 客户端在语法上是不正确的。"

在我看来:

当登录信息正确时,Model不为null。我可以从日志中看到这一点(见下文)。 当用户输入不符合验证要求时,AOP调用验证都已完成,但我的控制器方法甚至没有被调用(再次,请参阅日志)。

的JSP

登录表格:



<%@ page contentType="text/html; charset=UTF-8"%>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>

<html>
<head>
<title><spring:message code="label.login" /></title>
<style>
.error {
	color: red;
	font-weight: bold;
}
</style>
</head>
<body>



	<h2 align="center">
		<spring:message code="label.login" />
	</h2>
	<h2 align="center">
		<spring:message code="${loginError}" />
	</h2>
	<form:form method="POST" action="/prototype2/xz/doXzLogin" commandName="userAdminForm">
		<table>
			<tr>
				<td><form:label path="userName" >
						<spring:message code="label.name" />
						<form:errors path="userName" cssClass="error"/>
					</form:label></td>
				<td><form:input path="userName" /></td>
			</tr>
			<tr>
				<td><form:label path="password">
						<spring:message code="label.password" />
						<form:errors path="password" cssClass="error"/>
					</form:label></td>
				<td><form:input path="password" /></td>
			</tr>
			<tr>
				<td><form:label path="pin">
						<spring:message code="label.pin" />
						<form:errors path="pin" cssClass="error"/>
						
					</form:label></td>
				<td><form:input path="pin" /></td>
			</tr>
			<tr>
				<td colspan="2"><input type="submit" value="Submit" /></td>
			</tr>
		</table>
	</form:form>

</body>
</html>
&#13;
&#13;
&#13;

登录成功表格(暂时只是一个测试页面)

&#13;
&#13;
<%@ page contentType="text/html; charset=UTF-8" %>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>

<html>
<head>
<title><spring:message code="label.hello"/>:  ${userName}</title>
</head>
<body>


<h3 align="center"><spring:message code="label.hello"/>, ${userName}</h3>
  
  <form:form method="POST" action="/prototype2/performXzLogin" commandName="userAdminForm">
   <table>
    <tr>
        <td><form:label path="userName"><spring:message code="label.name"/></form:label></td>
        <td>${userName}</td>
    </tr>
    <tr>
        <td><form:label path="password"><spring:message code="label.password"/></form:label></td>
        <td>${password}</td>
    </tr>
    <tr>
        <td><form:label path="pin"><spring:message code="label.pin"/></form:label></td>
        <td>${pin}</td>
    </tr>
    
</table>  
</form:form>
   
</body>
</html>
&#13;
&#13;
&#13;

控制器

  package com.prototype2.controller.user;

  import javax.validation.Valid;

  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Controller;
  import org.springframework.ui.Model;
  import org.springframework.validation.BindingResult;
  import org.springframework.web.bind.annotation.ExceptionHandler;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.RequestMethod;

  import com.prototype2.controller.welcome.SS;
  import com.prototype2.controller.welcome.SpringException;
  import com.prototype2.model.user.UserAdmin;
  import com.prototype2.service.user.AdminUserService;
  import com.prototype2.service.user.BusinessService;

  @Controller
  public class UserControllerImpl
  {

   @Autowired
   private AdminUserService auService;

   @Autowired
   private BusinessService businessService;

   @RequestMapping(value = "/xzlogin", method = RequestMethod.GET)
   public String xzLogin(Model model)
   {

    UserAdmin ua = new UserAdmin();
    model.addAttribute("userAdminForm", ua);
    model.addAttribute("loginError", "label.blank");

    SS.getLogger().debug("xxx: xzLogin done");
    return "xzlogin";

   }

   @RequestMapping(value = "/doXzLogin", method = RequestMethod.POST)
   @ExceptionHandler(
   { SpringException.class })
   public String doXzLogin(@Valid UserAdmin u, Model model, BindingResult bindingResult)
   {

    SS.getLogger().debug("doXzLogin xxx UserAdmin: " + u.toString());
    SS.getLogger().debug("doXzLogin xxx Model size: " + model.toString());
    if (bindingResult.hasErrors())
    {
     model.addAttribute("loginError", "label.loginfailed");
     return "xzlogin";
    }
    SS.getLogger().debug("doing login: listing entries if any...");

    SS.getLogger().debug("User Logging In:   " + u.getUserName());
    try
    {

     model.addAttribute("userAdminForm", u);
     // model.addAttribute("userName", u.getUserName());

     // model.addAttribute("pin", u.getPin());

     // model.addAttribute("password", u.getPassword());

     if (auService.doAdminLogin(u))
     {

      return "xzloginresult";
     } else
     {
      model.addAttribute("loginError", "label.loginfailed");

      return "xzlogin";

     }
    } catch (Exception e)
    {
     SS.getLogger().error(e.getMessage(), e);
     throw new SpringException(e.getMessage() + "Login Failed: Incorrect username, password, or pin");
    }

   }

  }

的ApplicationContext

&#13;
&#13;
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="  
   http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
   http://www.springframework.org/schema/aop 
   http://www.springframework.org/schema/aop/spring-aop-3.2.xsd 
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context-3.1.xsd 
   http://www.springframework.org/schema/tx
   http://www.springframework.org/schema/tx/spring-tx-3.2.xsd 
   http://www.springframework.org/schema/mvc
   http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">

	<!-- i18n -->
	<bean id="messageSource"
		class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
		<property name="basename" value="classpath:messages" />
		<property name="defaultEncoding" value="UTF-8" />
	</bean>

	<bean id="localeChangeInterceptor"
		class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
		<property name="paramName" value="lang" />
	</bean>

	<bean id="localeResolver"
		class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
		<property name="defaultLocale" value="en" />
	</bean>

	<bean id="handlerMapping"
		class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
		<property name="interceptors">
			<ref bean="localeChangeInterceptor" />
		</property>
	</bean>

	<!-- Hibernate -->
	                        ...
	
	<!--  validation -->
	<mvc:annotation-driven validator="validator" />
	
	<bean id="validator"
    class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
</beans>
&#13;
&#13;
&#13;

成功登录的日志(没有错误,没有问题。模型不为空):

>>******Controller Log: Successful login******





>>
>>
>>[DEBUG] "jake.app" 2015-08-07 11:47:00,731: Locale  en
>>
>>[DEBUG] "jake.app" 2015-08-07 11:47:02,845: xxx: xzLogin done
>>
>>[DEBUG] "jake.app" 2015-08-07 11:47:14,305: doXzLogin xxx UserAdmin: UserAdmin [userName=jake0, password=1234, pin=1234, id=null]
>>
>>[DEBUG] "jake.app" 2015-08-07 11:47:14,306: doXzLogin xxx Model size: {userAdmin=UserAdmin [userName=jake0, password=1234, pin=1234, id=null], org.springframework.validation.BindingResult.userAdmin=org.springframework.validation.BeanPropertyBindingResult: 0 errors}
>>
>>[DEBUG] "jake.app" 2015-08-07 11:47:14,311: doing login: listing entries if any...
>>
>>[DEBUG] "jake.app" 2015-08-07 11:47:14,313: User Logging In:   jake0
>>
>>[DEBUG] "jake.app" 2015-08-07 11:47:14,503: in ua service
>>
>>[DEBUG] "jake.app" 2015-08-07 11:47:14,504: logging in through dao :jake0 1234 1234
>>
>>[DEBUG] "jake.app" 2015-08-07 11:47:14,972: User Admin is UserAdmin [userName=jake0, password=1234, pin=1234, id=206]
>>
>>[DEBUG] "jake.app" 2015-08-07 11:47:14,974: User Admin is UserAdmin [userName=jake0, password=1234, pin=1234, id=206]
>>
>>



******Root Log (i.e., Spring Log): Successful login******
>>
>>[DEBUG] 2015-08-07 11:47:14,297: org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:861) DispatcherServlet with name 'AssessmentAdmin' processing POST request for [/prototype2/xz/doXzLogin]
>>
    (cut for sake of brevity)
>>
>>[DEBUG] 2015-08-07 11:47:15,002: org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1616) Invoking afterPropertiesSet() on bean with name 'xzloginresult'
>>
>>[DEBUG] 2015-08-07 11:47:15,003: org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:248) Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
>>
>>[DEBUG] 2015-08-07 11:47:15,004: org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1241) Rendering view [org.springframework.web.servlet.view.InternalResourceView: name 'xzloginresult'; URL [/WEB-INF/jsp/xzloginresult.jsp]] in DispatcherServlet with name 'AssessmentAdmin'
>>
>>[DEBUG] 2015-08-07 11:47:15,005: org.springframework.web.servlet.view.AbstractView.exposeModelAsRequestAttributes(AbstractView.java:432) Added model object 'userAdmin' of type [jake.prototype2.model.user.UserAdmin] to request in view with name 'xzloginresult'
>>
>>[DEBUG] 2015-08-07 11:47:15,006: org.springframework.web.servlet.view.AbstractView.exposeModelAsRequestAttributes(AbstractView.java:432) Added model object 'org.springframework.validation.BindingResult.userAdmin' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'xzloginresult'
>>
>>[DEBUG] 2015-08-07 11:47:15,008: org.springframework.web.servlet.view.AbstractView.exposeModelAsRequestAttributes(AbstractView.java:432) Added model object 'userAdminForm' of type [jake.prototype2.model.user.UserAdmin] to request in view with name 'xzloginresult'
>>
>>[DEBUG] 2015-08-07 11:47:15,010: org.springframework.web.servlet.view.AbstractView.exposeModelAsRequestAttributes(AbstractView.java:432) Added model object 'org.springframework.validation.BindingResult.userAdminForm' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'xzloginresult'
>>
>>[DEBUG] 2015-08-07 11:47:15,012: org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:166) Forwarding to resource [/WEB-INF/jsp/xzloginresult.jsp] in InternalResourceView 'xzloginresult'
>>
>>[DEBUG] 2015-08-07 11:47:15,046: org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:996) Successfully completed request
>>

登录时验证错误(模型为空):**

>>******Controller Log: failed login******
>>
>>
>>[DEBUG] "jake.app" 2015-08-07 11:39:34,781: xxx: xzLogin done
>>
>>
>>
>>
>>


>>Root Log (i.e., Spring Log): failed login******
>>
>>
>>
>>[DEBUG] 2015-08-07 11:39:42,741: org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:248) Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
>>
>>[DEBUG] 2015-08-07 11:39:42,742: org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:478) Finished creating instance of bean 'org.hibernate.validator.internal.constraintvalidators.NotNullValidator'
>>
>>[DEBUG] 2015-08-07 11:39:42,749: org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450) Creating instance of bean 'org.hibernate.validator.internal.constraintvalidators.MinValidatorForNumber'
>>
>>[DEBUG] 2015-08-07 11:39:42,755: org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:248) Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
>>
>>[DEBUG] 2015-08-07 11:39:42,756: org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:478) Finished creating instance of bean 'org.hibernate.validator.internal.constraintvalidators.MinValidatorForNumber'
>>
>>[DEBUG] 2015-08-07 11:39:42,802: org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:134) Resolving exception from handler [public java.lang.String jake.prototype2.controller.user.UserControllerImpl.doXzLogin(jake.prototype2.model.user.UserAdmin,org.springframework.ui.Model,org.springframework.validation.BindingResult)]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
>>Field error in object 'userAdmin' on field 'pin': rejected value [0]; codes [Min.userAdmin.pin,Min.pin,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userAdmin.pin,pin]; arguments []; default message [pin],1000]; default message [must be greater than or equal to 1000]
>>
>>[DEBUG] 2015-08-07 11:39:42,807: org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:134) Resolving exception from handler [public java.lang.String jake.prototype2.controller.user.UserControllerImpl.doXzLogin(jake.prototype2.model.user.UserAdmin,org.springframework.ui.Model,org.springframework.validation.BindingResult)]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
>>Field error in object 'userAdmin' on field 'pin': rejected value [0]; codes [Min.userAdmin.pin,Min.pin,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userAdmin.pin,pin]; arguments []; default message [pin],1000]; default message [must be greater than or equal to 1000]
>>
>>[DEBUG] 2015-08-07 11:39:42,809: org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:134) Resolving exception from handler [public java.lang.String jake.prototype2.controller.user.UserControllerImpl.doXzLogin(jake.prototype2.model.user.UserAdmin,org.springframework.ui.Model,org.springframework.validation.BindingResult)]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
>>Field error in object 'userAdmin' on field 'pin': rejected value [0]; codes [Min.userAdmin.pin,Min.pin,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userAdmin.pin,pin]; arguments []; default message [pin],1000]; default message [must be greater than or equal to 1000]
>>
>>[DEBUG] 2015-08-07 11:39:42,812: org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:134) Resolving exception from handler [public java.lang.String jake.prototype2.controller.user.UserControllerImpl.doXzLogin(jake.prototype2.model.user.UserAdmin,org.springframework.ui.Model,org.springframework.validation.BindingResult)]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
>>Field error in object 'userAdmin' on field 'pin': rejected value [0]; codes [Min.userAdmin.pin,Min.pin,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userAdmin.pin,pin]; arguments []; default message [pin],1000]; default message [must be greater than or equal to 1000]
>>
>>[DEBUG] 2015-08-07 11:39:42,815: org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:134) Resolving exception from handler [public java.lang.String jake.prototype2.controller.user.UserControllerImpl.doXzLogin(jake.prototype2.model.user.UserAdmin,org.springframework.ui.Model,org.springframework.validation.BindingResult)]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
>>Field error in object 'userAdmin' on field 'pin': rejected value [0]; codes [Min.userAdmin.pin,Min.pin,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userAdmin.pin,pin]; arguments []; default message [pin],1000]; default message [must be greater than or equal to 1000]
>>
>>[DEBUG] 2015-08-07 11:39:42,817: org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1034) Null ModelAndView returned to DispatcherServlet with name 'AssessmentAdmin': assuming HandlerAdapter completed request handling
>>
>>[DEBUG] 2015-08-07 11:39:42,818: org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:996) Successfully completed request
>>
>>
>>******HTTP 400 message ******
>>The request sent by the client was syntactically incorrect.
>>
>>
>>
>>

1 个答案:

答案 0 :(得分:1)

密码检查应该是BindingResult验证的一部分。因此,在post的控制器方法中,我们手动将JSR-303错误添加到BindingResult。

if (bindingResult.hasErrors()){
       return "xzlogin"; 
    }


model.addAttribute("userAdminForm", u); 

if (!auService.doAdminLogin(u)){
bindingResult.addError(new FieldError("userAdminForm","password","Invalid password "));
return "xzlogin"; 
                }

这允许Spring通过FieldError在视图中显示它们