2013-05-25 39 views
2

我寫了一個自定義用戶詳細信息服務的Spring MVC應用程序。春季自定義用戶詳細信息服務空指針異常

@Service("userDetailsService") 
public class CustomUserDetailsService implements UserDetailsService{ 

    @Autowired 
    private UserAccountDao userAccountDao; 

    @Transactional(readOnly = true) 
    public UserDetails loadUserByUsername(String username) 
      throws UsernameNotFoundException { 

     UserDetails user = null; 
     try { 

      UserAccount dbUser = (UserAccount) userAccountDao.getByUsername(username); 

在這一點上,userAccountDao爲空,所以它拋出以上線,這將意味着自動裝配不在本服務內注入這道空指針異常。現在,道本身已自動裝配這樣...

@Repository("userAccountDao") 
public class UserAccountDaoImpl extends UserDaoImpl implements UserAccountDao { 

    @Autowired 
    private PasswordEncoder passwordEncoder; 

    @Autowired 
    private SessionFactory sessionFactory; 

    @Override 
    public void addUserAccount(final UserAccount userAccount) { 
     userAccount.setPassword(passwordEncoder.encodePassword(userAccount.getPassword(), "salt")); 
     sessionFactory.getCurrentSession().save(userAccount); 
    } 
} 



@Repository("userDao") 
public class UserDaoImpl implements UserDao { 

    @Autowired 
    private SessionFactory sessionFactory; 

    @Override 
    public User getByUsername(final String username) { 
     return (User) sessionFactory.getCurrentSession() 
       .createQuery("from User where username = :username") 
       .setParameter("username", username).uniqueResult(); 
    } 

現在這個確實做工精細,當我創建的用戶,從任何其他對象中獲取的用戶,它只是這個CustomUserDetailsS​​ervice這不是被正確注射。它與其他可以使用@Autowired罰款的服務在相同的包com.securetest.app.service中。

我有3個context.xml的文件 - 下面是我的web.xml

<?xml version="1.0" encoding="UTF-8"?> 
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    version="2.5"> 
    <context-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value>/WEB-INF/spring/root-context.xml 
      /WEB-INF/spring/appServlet/security-context.xml</param-value> 
    </context-param> 
    <filter> 
    <filter-name>springSecurityFilterChain</filter-name> 
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>springSecurityFilterChain</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 
<listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 
<servlet> 
    <servlet-name>appServlet</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <init-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value>/WEB-INF/spring/appServlet/servlet-context.xml 
     /WEB-INF/spring/appServlet/persistence-context.xml</param-value> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
</servlet> 
<servlet-mapping> 
    <servlet-name>appServlet</servlet-name> 
    <url-pattern>/</url-pattern> 
</servlet-mapping> 

這是我的安全context.xml的

<?xml version="1.0" encoding="UTF-8"?> 
<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.xsd 
        http://www.springframework.org/schema/security 
        http://www.springframework.org/schema/security/spring-security-3.1.xsd 
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 

    <http use-expressions="true"> 
     <intercept-url pattern="/exam" access="isAuthenticated()" /> 
     <intercept-url pattern="/" access="permitAll" /> 
     <intercept-url pattern="/**" access="denyAll" /> 
     <form-login /> 
     <logout invalidate-session="true" logout-success-url="/" 
      logout-url="/logout" /> 
    </http> 
    <beans:bean id="CustomUserDetailsService" 
     class="com.securetest.app.service.CustomUserDetailsService" /> 

    <beans:bean 
     class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" 
     id="passwordEncoder" /> 

    <authentication-manager> 
     <authentication-provider user-service-ref='CustomUserDetailsService'> 
      <password-encoder ref="passwordEncoder" /> 
     </authentication-provider> 
    </authentication-manager> 
</beans:beans> 

,最後只是爲了確保我沒有錯過任何東西,我的servlet-context.xml - 正如你所看到的,在這裏我使用上下文組件掃描,它應該注入一切在com.securetest.app

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

    <!-- DispatcherServlet Context: defines this servlet's request-processing 
     infrastructure --> 

    <!-- Enables the Spring MVC @Controller programming model --> 
    <annotation-driven /> 

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving 
     up static resources in the ${webappRoot}/resources directory --> 
    <resources mapping="/resources/**" location="/resources/" /> 

    <context:component-scan base-package="com.securetest.app." /> 
    <!-- Resolves views selected for rendering by @Controllers to .jsp resources 
     in the /WEB-INF/views directory --> 
    <beans:bean 
     class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
     <beans:property name="prefix" value="/WEB-INF/views/" /> 
     <beans:property name="suffix" value=".jsp" /> 
    </beans:bean> 
    <beans:bean 
     class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> 
     <beans:property name="mediaTypes"> 
      <beans:map> 
       <beans:entry key="html" value="text/html" /> 
       <beans:entry key="json" value="application/json" /> 
      </beans:map> 
     </beans:property> 
     <beans:property name="defaultViews"> 
      <beans:list> 
       <beans:bean 
        class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"> 
        <beans:property name="prefixJson" value="true" /> 
       </beans:bean> 
      </beans:list> 
     </beans:property> 
    </beans:bean> 

</beans:beans> 

我應該提,我敢肯定它的東西,就像我命令我的web.xml不正確,反之亦然,因爲幾乎一模一樣的代碼適用於其他項目,但我看不出之間的差異二。

爲什麼我得不到autowire失敗並且只是一個nullPointerException?

編輯:根context.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" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 


</beans> 
+0

什麼是root-context.xml? –

+0

我還沒有添加任何東西,但它顯示在上面。 – david99world

回答

3

你的web.xml文件中創建兩個Spring應用程序上下文。我們稱它們爲Security(在security-context.xml之後)和Servlet(在servlet-context.xml之後)。安全性由ContextLoaderListener偵聽器創建,Servlet由DispatcherServlet servlet創建。安全性是Servlet的父項。這意味着Security中的bean只對Security中的其他bean可見,並且Servlet中的bean可以在Security和Servlet中看到這兩個bean。

您正在定義Security中的CustomUserDetailsS​​ervice(CUDS)bean以及Servlet中的UserAccountDao和UserDao bean,因此CUDS bean無法看到它們。如果您希望將它們連接到CUDS,則需要在安全性中爲DAO bean添加組件掃描。

我不確定NPE。

+0

錯誤,對,因爲他們沒有被掃描。掃描他們是否解決了問題? –

+0

我想我的回答太簡單了。現在編輯它。 –

+0

所以你說我應該做另一個上下文:我的security-context.xml中的組件掃描?這似乎創建了一個beanCreationException – david99world

1

我認爲,您的安全上下文加載在您的servlet-context之前,該持有DAO的配置。當安全加載時,DAO沒有被掃描,因此沒有任何注入!使用@Required進行檢查。

我做了以下爲我的項目:

root-context.xml

<context:component-scan use-default-filters="true" 
     base-package="com.trelta.accountmanagement, com.trelta.commons"> 
     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
    </context:component-scan> 
中的servlet上下文

<context:component-scan use-default-filters="false" 
     base-package="com.trelta.accountmanagement, com.trelta.commons"> 
     <context:include-filter type="annotation" 
      expression="org.springframework.stereotype.Controller" /> 
    </context:component-scan> 

我把root-context.xml &的security.xml在context-paramservlet-context.xmlDispatcherServletinit-param。這種方法也增加了模塊性。它將您的WebApplicationContext相關的bean保留在一個文件中,然後將其傳遞到您的DispatcherServlet和您的其他ApplicationContext豆中一個單獨的文件中。

+0

這聽起來完全像。是由web.xml定義的順序還是僅在context.xml文件中的項目順序? – david99world

+0

在web.xml中。'context-param's首先加載。目前,只需xml注入dao並檢查而不是註釋。 –

+0

@Autowired bean默認是必需的。 –