DAO的NullPointerException

时间:2014-08-13 13:26:15

标签: spring hibernate dao sessionfactory

我在此方法中获取userDao的NullPointerException。 userDao确实是空的,但为什么以及如何解决它?

注意!问题已根据多个人的建议进行了更新。

public class UserServiceImpl implements UserService {

private UserDao userDao;

@Override
public UserDao getUserDao() {
    return userDao; // userDao is null
}

@Autowired
@Override
public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
}

@Override
public User add(User user) { 
    return getUserDao().insert(user);
}

@Override
public User get(String username) {
    return getUserDao().select(username);
}

@Override
public boolean userExists(String username) {
    return getUserDao().userExists(username); // throws NullPointerException (userDao is null -- confirmed with debugger)
}

用SpringMVC-config.xml中

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<bean id="tweetService"
      class="com.springapp.mvc.tweet.TweetServiceImpl">
    <property name="tweetDao" ref="tweetDao"/>
</bean>

<bean id="tweetDao"
      class="com.springapp.mvc.tweet.TweetDaoImpl">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<bean id="userService"
      class="com.springapp.mvc.user.UserServiceImpl">
    <property name="userDao" ref="userDao"/>
</bean>

<bean id="userDao"
      class="com.springapp.mvc.user.UserDaoImpl">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<bean id="followService"
      class="com.springapp.mvc.follow.FollowServiceImpl">
    <property name="followDao" ref="followDao"/>
</bean>

<bean id="followDao"
      class="com.springapp.mvc.follow.FollowDaoImpl">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

<bean id="sessionFactory"
      class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mappingResources">
        <list>
            <value>User.hbm.xml</value>
            <value>Tweet.hbm.xml</value>
            <value>Follow.hbm.xml</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="dialect">org.hibernate.dialect.H2Dialect</prop>
            <prop key="current_session_context_class">thread</prop>
            <prop key="hbm2ddl.auto">update</prop>
            <prop key="connection.pool_size">1</prop>
        </props>
    </property>
</bean>

<bean id="dataSource"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.h2.Driver"/>
    <property name="url" value="jdbc:h2:tcp://localhost/~/twitter"/>
    <property name="username" value=""/>
    <property name="password" value=""/>
</bean>

<bean id="dbUtil"
      class="com.springapp.mvc.util.DbUtil"
      init-method="initialize">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!-- register all beans except controllers -->
<context:component-scan base-package="com.springapp.mvc">
    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>

</beans>

的web.xml

 <web-app version="2.4"
     xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<display-name>Spring MVC Application</display-name>

<!-- intercepts requests -->
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<!-- protected URL path -->
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- location of Config -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath:/applicationContext-security.xml
        classpath:/springmvc-config.xml
    </param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- dispatches requests to controllers -->
<servlet>
    <servlet-name>mvc-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<!-- maps requests to path to mvc-dispatcher -->
<servlet-mapping>
    <servlet-name>mvc-dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>


</web-app>

MVC-调度-servlet.xml中

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<context:component-scan base-package="com.springapp.mvc">
    <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>

<mvc:annotation-driven/>

<mvc:resources mapping="/css/**" location="/css/"/>

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/pages/"/>
    <property name="suffix" value=".jsp"/>
</bean>

<mvc:resources mapping="/js/**" location="/js/**"/>
<mvc:resources mapping="/css/**" location="/css/**"/>
<mvc:resources mapping="/fonts/**" location="/fonts/**"/>

</beans>

的applicationContext-security.xml文件

<?xml version="1.0" encoding="UTF-8"?>

<!-- security context -->
<beans:beans xmlns="http://www.springframework.org/schema/security"
         xmlns:beans="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
         http://www.springframework.org/schema/security
         http://www.springframework.org/schema/security/spring-security.xsd">

    <http auto-config="true">
    <intercept-url pattern="/home/**" access="IS_AUTHENTICATED_FULLY"/>
    <intercept-url pattern="/users/**" access="IS_AUTHENTICATED_FULLY"/>
    <intercept-url pattern="/tweet/**" access="IS_AUTHENTICATED_FULLY"/>
    <form-login
            login-page="/login"
            default-target-url="/login?success"
            authentication-failure-url="/login?error"
            username-parameter="username"
            password-parameter="password"
            />
    <logout
            logout-url="/logout"
            logout-success-url="/"
            />
</http>

    <authentication-manager>
    <authentication-provider user-service-ref="userAccountDetailsService">
    </authentication-provider>
</authentication-manager>

<beans:bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"/>

</beans:beans>

UserController.java

@Controller
public class UserController {

private static final Log logger = LogFactory.getLog(UserController.class);

@Autowired
private UserService userService;

@Autowired
private TweetService tweetService;

@Autowired
private FollowService followService;

@RequestMapping(value = {"/"})
public String landingPage() {
    logger.info("landingPage called");
    return "LandingPage";
}

@RequestMapping("/register")
public ModelAndView registerUser() {
    logger.info("registerUser called");
    ModelAndView model = new ModelAndView();
    User user = new User();
    model.addObject(user);
    model.setViewName("RegistrationForm");
    return model;
}

@RequestMapping(value = "/user_save", method = RequestMethod.POST)
public String saveUser(@ModelAttribute User user, BindingResult bindingResult) {
    logger.info("saveUser called");

    // validate form input
    UserValidator userValidator = new UserValidator();
    userValidator.validate(user, bindingResult); // NullPointerException occurs on this line, see validator below

    // if errors are found, return to registration form and display errors
    if (bindingResult.hasErrors()) {
        if (bindingResult.hasErrors()) {
            FieldError fieldError = bindingResult.getFieldError();
            logger.info("Code: " + fieldError.getCode() + ", field: " + fieldError.getField());
            return "RegistrationForm";
        }
    }

    // saveTweet user to database
    userService.add(user);
    return "LoginForm";
}
...

验证方法:

...
public void validate(Object target, Errors errors) {
    User user = (User) target;
    // confirm that required fields are filled in
    ValidationUtils.rejectIfEmpty(errors, "name", "name.required", "Error msg...");
    ValidationUtils.rejectIfEmpty(errors, "username", "username.required", "Error msg...");
    ValidationUtils.rejectIfEmpty(errors, "password", "password.required", "Error msg...");
    // if the user has filled in a username, check if if already exists
    String username = user.getUsername();
    UserService userService = new UserServiceImpl();
    if (username != null && userService.userExists(username)) { // this calls the userExists() method that causes a NullPointerException
        errors.rejectValue("username", "username.exists", "Error msg...");
    }
}
...

2 个答案:

答案 0 :(得分:3)

您已在mvc-dispatcher-servlet.xml中启用了组件扫描。这会导致您的UserServiceImpl bean在两个不同的上下文中注册。根应用程序上下文(由于显式XML配置而在其中注册)以及Web应用程序上下文(通过组件扫描进行注册)。

(查看this以了解有关两种情境之间差异的更多信息)

通常的做法是在根应用程序上下文中注册除控制器之外的所有bean(在您的情况下通过springmvc-config.xml)。然后,控制器将在Web应用程序上下文中注册(在您的情况下通过mvc-dispatcher-servlet.xml)。

因此,在您的情况下,您可以将springmvc-config.xml中的组件扫描更改为

<context:component-scan base-package="com.springapp.mvc">
    <context:exclude-filter expression="org.springframework.stereotype.Controller"
        type="annotation"/>
</context:component-scan>

并在mvc-dispatcher-servlet.xml

<context:component-scan base-package="com.springapp.mvc">
    <context:include-filter expression="org.springframework.stereotype.Controller"
        type="annotation"/>
</context:component-scan>.

前一个组件扫描会强制Spring获取除com.springapp.mvc之外的任何构造型注释所注释的所有类(在@Controller下),而后者仅包含@Controller注释类。< / p>

此外,您在@Service上有刻板印象UserServiceImpl。删除它,因为您在XML中显式配置bean,并且组件扫描不应该选择类。

单独注意,配置

<mvc:annotation-driven/>
<mvc:resources mapping="/css/**" location="/css/"/>

属于mvc-dispatcher-servlet.xml,而不属于springmvc-config.xml

<强>更新

您正在使用

获取UserServiceImpl

UserService userService = new UserServiceImpl();

这意味着你没有使用Spring来获取它。 您需要删除它并使用从

获得的引用
@Autowired
private UserService userService
UserValidator中的

。那当然意味着UserValidator也必须是一个Spring bean。

所以你有

@Component
public class UserValidator {

   @Autowired
   private UserService userService;

    public void validate(Object target, Errors errors) {
      User user = (User) target;
      // confirm that required fields are filled in
      ValidationUtils.rejectIfEmpty(errors, "name", "name.required", "Error msg...");
      ValidationUtils.rejectIfEmpty(errors, "username", "username.required", "Error msg...");
      ValidationUtils.rejectIfEmpty(errors, "password", "password.required", "Error msg...");
      // if the user has filled in a username, check if if already exists
      String username = user.getUsername();
      if (username != null && userService.userExists(username)) { // this calls the userExists() method that causes a NullPointerException
        errors.rejectValue("username", "username.exists", "Error msg...");
      }
   }

}

你需要添加

@Autowired
private UserValidator userValidator
<{1>}中的

(同时还删除了UserController

答案 1 :(得分:-1)

在这种情况下,您的对象不会被注入,因此它是空的。

您可以使用@Autowired注释,并且可以使用上下文命名空间的组件扫描启用它

<context:component-scan  base-package="XXX"/>

或者定义setter方法,因为我可以看到你在bean defination中给出了属性 所以你可以为DAO提供需要注入的setter方法。

xml文件:

<bean id="userService"
      class="com.springapp.mvc.user.UserServiceImpl">
    <property name="userDao" ref="userDao"/>
</bean>

UserServiceImpl

public void setUserDAO(UserDAO userDAO){
    this.userDAO=userDAO;
}