我在此方法中获取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...");
}
}
...
答案 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;
}