0

我正在使用 Java EE、Spring、EclipseLink 和 Glassfish 服务器开发一个 Web 应用程序。

在我尝试更改我的 bean 配置以便用 Spring 注入 entitymanager 并启用更好的事务管理之前,我的应用程序工作得很好......我没有让它工作......(在此之前我拥有所有一样,除了我必须在每个数据库请求之前调用 emf.createEntityManager() )。

这是我的配置文件:

  • 网页.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:jsp="http://java.sun.com/xml/ns/javaee/jsp"
    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_3_0.xsd"
    id="WebApp_ID" version="3.0">
    
     <!-- jsp config => automatic inclusions in all jsp files -->
    <jsp-config>
       <jsp-property-group>
         <url-pattern>/WEB-INF/views/*</url-pattern>
        <include-prelude>taglibs.jsp</include-prelude>
        <include-prelude>setLanguage.jsp</include-prelude>
    </jsp-property-group>
    </jsp-config>
    <display-name>MEANS</display-name>
    
    <!-- Beans in these files will makeup the configuration of the root web 
    application context -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/applicationContext.xml</param-value>
    </context-param>
    
     <!-- Bootstraps the root web application context before servlet initialization -->
      <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
    
    <!-- Deploys the 'dispatcher' dispatcher servlet whose configuration resides 
    in /WEB-INF/spring/mvc-config.xml -->
     <servlet>
        <servlet-name>dispatcher</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/mvc-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
       <servlet-name>dispatcher</servlet-name>
       <url-pattern>*.do</url-pattern><!-- detect all urls ending with ".do" -->
    </servlet-mapping>
    
    <!-- Security Spring filter -->
    <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>
    
    <session-config>
       <session-timeout>30</session-timeout><!-- the session is automatically 
        disconnected after 30 min of inactivity -->
    </session-config>
    
     <listener id="myLogger">
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
     </listener>
    
    <welcome-file-list>
         <welcome-file>index.do</welcome-file>
      </welcome-file-list>
    </web-app>
    
  • 安全配置.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:util="http://www.springframework.org/schema/util"
         xmlns:security="http://www.springframework.org/schema/security"
         xsi:schemaLocation="http://www.springframework.org/schema/beans 
                       http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
                       http://www.springframework.org/schema/util 
                       http://www.springframework.org/schema/util/spring-util-3.1.xsd
                       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    
        <security:authentication-manager><!-- custom authentication manager-->
          <security:authentication-provider
        user-service-ref="userService">
          <security:password-encoder ref="passwordEncoder">
             <security:salt-source user-property="username" />
           </security:password-encoder>
          </security:authentication-provider>
        </security:authentication-manager>
    
       <bean id="passwordEncoder"
    class="org.springframework.security.authentication.encoding.MessageDigestPasswordEncoder">
    <constructor-arg value="MD5" />
      </bean>
    
      <bean id="userService" class="fr.services.security.MyUserDetailsService"><!-- custom userDetailService -->
            <constructor-arg ref="myDAOFactory"/>
      </bean>
    
       <!-- disable authentication for those free access components-->
       <security:http pattern="/login.jsp*" security="none" />
       <security:http pattern="/disconnected.jsp*" security="none" />
       <security:http pattern="/css/**" security="none" />
       <security:http pattern="/javascript/**" security="none" />
       <security:http pattern="/jquery/**" security="none" />
    
      <security:http access-denied-page="/denied.jsp"   use-expressions="true">
    <security:form-login login-page="/login.jsp"
        authentication-failure-url="/login.jsp?errorMessage=invalidConnection"
        default-target-url='/index.do' always-use-default-target='false' />
    <security:intercept-url pattern="/admin*.do"
        access="hasRole('ROLE_ADMINISTRATEUR')" />
    <security:intercept-url pattern="/access*.do"
        access="isAnonymous() or isAuthenticated()" />
    <security:intercept-url pattern="/**"
        access="isAuthenticated()" />
    <security:logout logout-success-url="/disconnected.jsp" />
      </security:http>
    
       </beans>
    
  • 持久性配置.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:p="http://www.springframework.org/schema/p"
       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.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    
    
      <bean id="dataSource"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource"
      p:driverClassName="org.postgresql.Driver"
      p:url="jdbc:postgresql://localhost:5432/databaseName"
      p:username="postgres"
      p:password="pwd" />
    
     <tx:annotation-driven/>
    
     <tx:jta-transaction-manager>
       <property name="entityManagerFactory" ref="entityManagerFactory" />
     </tx:jta-transaction-manager>
    
     <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
      <property name="persistenceUnitName" value="databaseName" />
     </bean>
    
     <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
       <property name="entityManagerFactory" ref="entityManagerFactory" />
      </bean>
     <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    
    </beans>
    
  • 应用程序上下文.xml:

    <?xml version="1.0" encoding="UTF-8"?>
     <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:p="http://www.springframework.org/schema/p"
         xmlns:aop="http://www.springframework.org/schema/aop"
        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.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
      <import resource="persistence-config.xml"/>
      <import resource="security-config.xml"/>
    
      <context:component-scan base-package="fr" />
    
      <context:annotation-config/>
    
    
        <!--  Define the location of the property file to change properties dependent on the application environment -->
         <context:property-placeholder location="/WEB-INF/configuration.properties" />
    
    </beans>
    
  • mvc-config.xml:

       <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"
        xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
            http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
            http://www.springframework.org/schema/tx  
            http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context.xsd">
    
     <import resource="persistence-config.xml"/>
     <import resource="security-config.xml"/>
    
    
        <!-- Spring MVC Support for annotations (JSR-303) -->
      <mvc:annotation-driven>
    
      </mvc:annotation-driven>
    
      <context:component-scan base-package="fr.controller, fr.dao, fr.services" />
    
      <bean id="viewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver"
    p:prefix="/WEB-INF/views/" p:suffix=".jsp" />
    
      <bean id="urlMap" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
       <property name="urlMap">
        <map>
            <entry key="accessPasswordLost.do" value-ref="urlFilenameViewController"/>
            <entry key="documentation.do" value-ref="urlFilenameViewController"/>
            <entry key="hierarchyDialog.do" value-ref="urlFilenameViewController"/>
            <entry key="nameDialog.do" value-ref="urlFilenameViewController"/>
            <entry key="openCopyDialog.do" value-ref="urlFilenameViewController"/>
            <entry key="tableErosionParameterLS.do" value-ref="urlFilenameViewController"/>
            <entry key="training.do" value-ref="urlFilenameViewController"/>
            <entry key="userSettings.do" value-ref="urlFilenameViewController"/>
        </map>
    </property>
      </bean>
      <!-- For direct mapping between URL (i.e. index.htm index) and the JSP to render -->
       <bean id="urlFilenameViewController"
    class="org.springframework.web.servlet.mvc.UrlFilenameViewController">
       </bean>
    
       <import resource="aspects-config.xml"/>
    
     </beans>
    

我不确定持久性配置和安全配置的导入...

为确保您掌握了所有信息,这里是注入实体管理器的 MyDAOFactory 类:

 /**
 * A factory for creating DAO objects.
 */
@Component
public class MyDAOFactory implements IMyDAOFactory{

/** The map dao. */
private Map<Class<?>, IDao<?>> mapDAO;

/** The entity manager. */
@PersistenceContext(unitName="databaseName")
public EntityManager em;


/**
 * Instantiates a new my dao factory.
 */

public MyDAOFactory() {

    mapDAO = new HashMap<Class<?>, IDao<?>>();

}


/**
 * Gets the em.
 *
 * @return the em
 */
public EntityManager getEm() {
    return em;
}

/**
 * Sets the em.
 *
 * @param emf the new em
 */
public void setEm(EntityManager em) {
    this.em = em;
}



@Override
public <T extends Serializable> IDao<T> getBasicDAO(Class<T> entity) {
    if(mapDAO.containsKey(entity)){
        return (IDao<T>) mapDAO.get(entity);
    }else{
        BasicDAO<T> dao = new BasicDAO<T>(entity);
        dao.setEm(em);
        mapDAO.put(entity,  dao);
        return dao;
    }
}

}

以及自定义的 UserDetailsS​​ervice:

  @Transactional
  public class MyUserDetailsService implements UserDetailsService {

  /** The my dao factory. */
  IMyDAOFactory myDAOFactory;

/**
 * Instantiates a new means user details service.
 *
 */
public MyUserDetailsService(IMyDAOFactory myDAOFactory) {
    this.myDAOFactory = myDAOFactory;
}


/* (non-Javadoc)
 * @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)
 */
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException{
    IDao<Utilisateur> userDAO = this.myDAOFactory.getBasicDAO(Utilisateur.class);
    Map<String, String> map = new HashMap<String, String>();
    map.put("loginLdap", username);
    Utilisateur user = userDAO.findByAttributes(map).get(0);
    IMyUserDetails userDetails = new MyUserDetails(user.getLoginLdap(), user.getPwdLocal(), user.getActif(), user.getDateValidite().getTime()>System.currentTimeMillis(), true, true, AuthorityUtils.createAuthorityList("ROLE_"+user.getProfil().getNomProfil().toUpperCase()));
    userDetails.setUser(user);
    return userDetails;     
}

 }

当我以调试模式启动服务器时,似乎在将 myDAOFactory 注入 MyUserDetailsS​​ervice 时设置了实体管理器,但是当我尝试登录我的应用程序时,对 loadUserByName 的调用不再发生......(虽然我没有更改这部分配置...)。

任何帮助都将不胜感激!

4

2 回答 2

1

几点建议:

  1. 不要在 MVC 配置中导入安全性和持久性配置,它们已经在根应用程序上下文(通过导入)中定义,其 bean 对 MVC 上下文可见

  2. DriverManagerDataSource 仅在测试中可用,最迟在生产中将其替换为真正的池化 DataSource(例如,通过 JNDI 查找的容器管理的 DataSource)

  3. 查看您的 DataSource 配置,您可能没有使用 JTA。如果是这样,请删除<tx:jta-transaction-manager />bean 定义

  4. 调试以尝试查明问题。如果它与持久性相关,则从一个最小的根应用程序上下文开始,其中只有持久性(JPA)的东西和一个简单的 bean 来测试它:

    <bean class="pkg.Test" init-method="persistence" />

  5. 如果您无法使其正常工作,请在此处发布更多信息

于 2013-06-04T21:09:51.167 回答
0

在尝试了几天所有可能的配置之后,我终于找到了使用 spring、eclipseLink 和 Glassfish 进行事务管理的正确解决方案:

  • 主要问题是由于错误使用了我在 applicationContext.xml 和 mvc-config.xml 中包含的 spring 标签 context:component scan。显然,它创建了 2 个不共享 bean 或事务的不同上下文(请参阅:为什么 DispatcherServlet 创建另一个应用程序上下文?
  • 我还测试了 JTA、jndi:lookup 和 LocalEntityManagerFactoryBean 之间的许多不同配置,但使用 Glassfish 和 EclipseLink 似乎使其更具限制性(JTA 是唯一可行的选择)

如果有一天它可以帮助某人,这是我的更正:

应用程序上下文.xml

<beans ...>

  <import resource="persistence-config.xml"/>
  <import resource="security-config.xml"/>

  <context:component-scan base-package="fr.dao, fr.services" /><!-- do not scan the controllers here  -->

  <context:annotation-config/>


  <!--  Define the location of the property file to change properties dependent on the application environment -->
  <context:property-placeholder location="/WEB-INF/configuration.properties" />

</beans>

mvc-config.xml

<beans >


<!-- Spring MVC Support for annotations (JSR-303) -->
<mvc:annotation-driven>
    <mvc:argument-resolvers>
        <bean class="fr.utils.CurrentUserWebArgumentResolver"></bean>
    </mvc:argument-resolvers>
</mvc:annotation-driven>

<context:component-scan base-package="fr.controller" /><!-- only scan controllers here -->

... 

<import resource="aspects-config.xml"/>

</beans>

还有persistence-config.xml:

<beans ...>

 <tx:annotation-driven/>

 <!-- We want to locate the container transaction manager -->
 <bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="jpaVendorAdapter">
        <bean
            class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
            <property name="showSql" value="true" />
        </bean>
    </property>
    <property name="jpaDialect">
        <bean
            class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect" />
    </property>
    <property name="persistenceUnitName" value="databaseName"/>
    <property name="persistenceUnitManager">
        <bean 
            class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager"/>
    </property>
  </bean>   

  <tx:jta-transaction-manager/>

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
</beans>
于 2013-06-10T16:39:46.053 回答