使用MyEclipse集成SSH整合Spring和Hibernate

开发环境:

JDK 1.5
Tomcat 6.0
Spring 2.5
Struts 1.3
Hibernate 3.2
DWR 2.0
MyEclipse 6.5
SQL Server 2005
--------------------------------------------------------------------------------

Spring整合Hibernate的价值在于Spring为Hibernate增加了以下内容:
* Session management:Spring为Hibernate的session提供了有效、容易和安全的控制
* Resource management:Spring控制Hibernate的SessionFactories,JDBC datasources及其它相关资源
* Integrated transaction management:完整的事务管理
* Exception wrapping:异常的包装

 

1. 利用Spring IoC容器创建SessionFactory

可以使用org.springframework.orm.hibernate3.LocalSessionFactoryBean创建 SessionFactory实例,共有以下二种方式:
1) 【最佳方案】直接使用Hibernate配置文件hibernate.cfg.xml
Hibernate配置文件 hibernate.cfg.xml如下:

 

Xml代码 <?xml version='1.0' encoding='UTF-8'?> 
<!DOCTYPE hibernate-configuration PUBLIC 
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 
         "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 
<hibernate-configuration> 
    <session-factory> 
        <property name="myeclipse.connection.profile"> 
                com.microsoft.sqlserver.jdbc.SQLServerDriver 
        </property> 
        <property name="connection.url"> 
                jdbc:sqlserver://localhost:1433;databaseName=SSH 
        </property> 
        <property name="connection.username">sa</property> 
        <property name="connection.password"></property> 
        <property name="connection.driver_class"> 
                com.microsoft.sqlserver.jdbc.SQLServerDriver 
        </property> 
        <property name="dialect"> 
                org.hibernate.dialect.SQLServerDialect 
        </property> 
        <mapping resource="cn/qdqn/ssh/entity/UserInfo.hbm.xml" /> 
    </session-factory> 
</hibernate-configuration> 
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
         "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="myeclipse.connection.profile">
                com.microsoft.sqlserver.jdbc.SQLServerDriver
        </property>
        <property name="connection.url">
                jdbc:sqlserver://localhost:1433;databaseName=SSH
        </property>
        <property name="connection.username">sa</property>
        <property name="connection.password"></property>
        <property name="connection.driver_class">
                com.microsoft.sqlserver.jdbc.SQLServerDriver
        </property>
        <property name="dialect">
                org.hibernate.dialect.SQLServerDialect
        </property>
        <mapping resource="cn/qdqn/ssh/entity/UserInfo.hbm.xml" />
    </session-factory>
</hibernate-configuration>
 

Spring配置文件中SessionFactory初始化配置方法:

Xml代码 <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
        <property name="configLocation" 
            value="classpath:hibernate.cfg.xml"> 
        </property> 
</bean> 
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="configLocation"
            value="classpath:hibernate.cfg.xml">
        </property>
</bean>

2) 在Spring配置文件中整合所有Hibernate配置参数

 

Xml代码 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
        <property name="driverClassName"  
                          value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/> 
        <property name="url"  
                          value="jdbc:sqlserver://localhost:1433;databaseName=SSH"/> 
        <property name="username" value="sa"/> 
        <property name="password" value=""/> 
</bean> 
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
        <property name="dataSource" ref="dataSource"> 
        </property> 
        <property name="mappingResources"> 
            <list> 
               <value>cn/qdqn/ssh/entity/UserInfo.hbm.xml</value> 
            </list> 
        </property> 
        <property name="hibernateProperties"> 
            <props> 
                <prop key="hibernate.dialect"> 
                     org.hibernate.dialect.SQLServerDialect 
                </prop> 
                <prop key="show_sql">true</prop> 
            </props> 
        </property> 
</bean> 
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName"
                          value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
        <property name="url"
                          value="jdbc:sqlserver://localhost:1433;databaseName=SSH"/>
        <property name="username" value="sa"/>
        <property name="password" value=""/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource">
        </property>
        <property name="mappingResources">
            <list>
               <value>cn/qdqn/ssh/entity/UserInfo.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">
                     org.hibernate.dialect.SQLServerDialect
                </prop>
                <prop key="show_sql">true</prop>
            </props>
        </property>
</bean>

  注意:使用MyEclipse集成SSH 时,org.apache.commons.dbcp.BasicDataSource所在的包commons-dbcp-1.2.2.jar不会默认加 载,另外还需加载commons-pool-1.4.jar,两者均可在Apache网站commons项目下找到。否则运行程序会出现以下异常:

 

Exception 代码 java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool 
at java.lang.Class.getDeclaredConstructors0(Native Method) 
at java.lang.Class.privateGetDeclaredConstructors(Unknown Source) 
at java.lang.Class.getConstructor0(Unknown Source) 
at java.lang.Class.getDeclaredConstructor(Unknown Source) 
…… 
java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Unknown Source)
at java.lang.Class.getConstructor0(Unknown Source)
at java.lang.Class.getDeclaredConstructor(Unknown Source)
……
2. Hibernate DAO开发


1) 使用Hibernate原生API实现DAO
A. 使用原生API实现DAO

 

Java代码 public class UserInfoDAORaw implements IUserInfoDAO { 
    private SessionFactory sessionFactory; 
    public SessionFactory getSessionFactory() { 
        return sessionFactory; 
    } 
    public void setSessionFactory(SessionFactory sessionFactory) { 
        this.sessionFactory = sessionFactory; 
    } 
    public List findAll() { 
        return this.sessionFactory.getCurrentSession() 
                                                               .createQuery("from UserInfo").list(); 
    } 
部 分代码省略…… 

public class UserInfoDAORaw implements IUserInfoDAO {
    private SessionFactory sessionFactory;
    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    public List findAll() {
        return this.sessionFactory.getCurrentSession()
                                                               .createQuery("from UserInfo").list();
    }
部分代码省略……
}

   B. 在applicationContext.xml配置原生DAO Bean 

 

Xml代码 <bean id="userInfoDAORaw" class="cn.qdqn.ssh.dao.UserInfoDAORaw"> 
        <property name="sessionFactory"> 
            <ref bean="sessionFactory" /> 
        </property> 
</bean> 
<bean id="userInfoDAORaw" class="cn.qdqn.ssh.dao.UserInfoDAORaw">
        <property name="sessionFactory">
            <ref bean="sessionFactory" />
        </property>
</bean>

   C. 运行测试

 

Java代码 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); 
UserInfoDAORaw dao=(UserInfoDAORaw)ctx.getBean("userInfoDAORaw"); 
List<UserInfo> list=dao.findAll(); 
for(UserInfo info : list){ 
        System.out.println(info.getUserName()+"-"+info.getUserPwd()); 

ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
UserInfoDAORaw dao=(UserInfoDAORaw)ctx.getBean("userInfoDAORaw");
List<UserInfo> list=dao.findAll();
for(UserInfo info : list){
        System.out.println(info.getUserName()+"-"+info.getUserPwd());
}
结论:使用Hibernate原生API实现DAO可以做到Hibernate和Spring完全分离,缺点是无法利用Spring 封装Hibernate所提供的额外功能。


2)【最佳方案】使用Spring框架所提供的HibernateDaoSupport类实现DAO
A. 使用MyEclipse反向工程生成Spring 整合Hibernate 的DAO,该DAO继承自Spring的 org.springframework.orm.hibernate3.support.HibernateDaoSupport 

 

Java代码 public class UserInfoDAO extends HibernateDaoSupport { 
    private static final Log log = LogFactory.getLog(UserInfoDAO.class); 
    // property constants 
    public static final String USER_NAME = "userName"; 
    public static final String USER_PWD = "userPwd"; 
 
    public void save(UserInfo transientInstance) { 
        log.debug("saving UserInfo instance"); 
        try { 
            getHibernateTemplate().save(transientInstance); 
            log.debug("save successful"); 
        } catch (RuntimeException re) { 
            log.error("save failed", re); 
            throw re; 
        } 
    } 
部 分代码省略…… 

public class UserInfoDAO extends HibernateDaoSupport {
    private static final Log log = LogFactory.getLog(UserInfoDAO.class);
    // property constants
    public static final String USER_NAME = "userName";
    public static final String USER_PWD = "userPwd";

    public void save(UserInfo transientInstance) {
        log.debug("saving UserInfo instance");
        try {
            getHibernateTemplate().save(transientInstance);
            log.debug("save successful");
        } catch (RuntimeException re) {
            log.error("save failed", re);
            throw re;
        }
    }
部分代码省略……
}

   B. 在applicationContext.xml配置DAO Bean 

 

Xml代码 <bean id="userInfoDAO" class="cn.qdqn.ssh.dao.UserInfoDAO"> 
        <property name="sessionFactory"> 
            <ref bean="sessionFactory" /> 
        </property> 
</bean> 
<bean id="userInfoDAO" class="cn.qdqn.ssh.dao.UserInfoDAO">
        <property name="sessionFactory">
            <ref bean="sessionFactory" />
        </property>
</bean>

   C. 运行测试

 

Java代码 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); 
UserInfoDAORaw dao=(UserInfoDAORaw)ctx.getBean("userInfoDAO"); 
List<UserInfo> list=dao.findAll(); 
for(UserInfo info : list){ 
System.out.println(info.getUserName()+"-"+info.getUserPwd()); 

ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
UserInfoDAORaw dao=(UserInfoDAORaw)ctx.getBean("userInfoDAO");
List<UserInfo> list=dao.findAll();
for(UserInfo info : list){
System.out.println(info.getUserName()+"-"+info.getUserPwd());
}

  注意:HibernateDaoSupport通过getHibernateTemplate()方法得到HibernateTemplate 实例进行保存、删除等操作,但是HibernateTemplate默认不进行事务处理,而在Hibernate中这些操作必须在事务下执行才能得到正确 的结果,因此必须使用Spring声明式事务管理。


3. 使用Spring声明式事务管理

1) 使用Spring 1.x 的事务代理类进行事务管理
A. 在applicationContext.xml中声明事务管理器,注入sessionFactory属性

Xml代码 <bean id="transactionManager" 
    class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
        <property name="sessionFactory"> 
            <ref local="sessionFactory" /> 
        </property> 
</bean> 
<bean id="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref local="sessionFactory" />
        </property>
</bean>

   B. 在applicationContext.xml中使用Spring AOP代理方式实现声明式事务

 

Xml代码 <bean id="userInfoDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
        <!--必须为true时CGLIB才不用强制编写DAO接口--> 
        <property name="proxyTargetClass"> 
            <value>true</value> 
        </property> 
        <property name="transactionManager"> 
            <ref bean="transactionManager"/> 
        </property> 
        <property name="target"> 
            <ref bean="userInfoDAO"/> 
        </property> 
        <property name="transactionAttributes"> 
            <props> 
                <prop key="*">PROPAGATION_REQUIRED</prop> 
            </props> 
        </property> 
</bean> 
<bean id="userInfoDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <!--必须为true时CGLIB才不用强制编写DAO接口-->
        <property name="proxyTargetClass">
            <value>true</value>
        </property>
        <property name="transactionManager">
            <ref bean="transactionManager"/>
        </property>
        <property name="target">
            <ref bean="userInfoDAO"/>
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
</bean>

       C. 通过代理Bean获取DAO Bean,进行数据库操作

 

Java代码 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); 
UserInfoDAO dao=(UserInfoDAO)ctx.getBean("userInfoDAOProxy"); 
UserInfo user=new UserInfo(); 
user.setUserName("比尔盖茨"); 
user.setUserPwd("windows"); 
dao.save(user); 
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
UserInfoDAO dao=(UserInfoDAO)ctx.getBean("userInfoDAOProxy");
UserInfo user=new UserInfo();
user.setUserName("比尔盖茨");
user.setUserPwd("windows");
dao.save(user);

  问题1:运行程序会报以下异常:

 

Exception 代码 java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V 
    at net.sf.cglib.core.ClassEmitter.begin_class(ClassEmitter.java:77) 
    at net.sf.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:173) 
    at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25) 
    at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216) 
    at net.sf.cglib.core.KeyFactory$Generator.create(KeyFactory.java:145) 
    at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:117) 
    at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:108) 
    at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:104) 
    at net.sf.cglib.proxy.Enhancer.<clinit>(Enhancer.java:69) 
………… 
java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V
    at net.sf.cglib.core.ClassEmitter.begin_class(ClassEmitter.java:77)
    at net.sf.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:173)
    at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
    at net.sf.cglib.core.KeyFactory$Generator.create(KeyFactory.java:145)
    at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:117)
    at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:108)
    at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:104)
    at net.sf.cglib.proxy.Enhancer.<clinit>(Enhancer.java:69)
…………
解决方法:原因是Spring与Hibernate所使用的asm版本冲突,删除asm.2.2.3.jar即可。
问题2: 对每个业务逻辑Bean或DAO Bean都要设置事务代理Bean将是一个非常庞大的工作量!
改进方法: 可以通过定义“基类”来解决重复性编码!如:

 

Xml代码 <bean id="baseDAOProxy" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
        <property name="proxyTargetClass"> 
            <value>true</value> 
        </property> 
        <property name="transactionManager"> 
            <ref bean="transactionManager"/> 
        </property> 
        <property name="transactionAttributes"> 
            <props> 
                <prop key="*">PROPAGATION_REQUIRED</prop> 
            </props> 
        </property> 
</bean> 
     
<bean id="userInfoDAOProxy" parent="baseDAOProxy"> 
        <property name="target"> 
            <ref bean="userInfoDAO"/> 
        </property> 
</bean> 
<bean id="baseDAOProxy" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="proxyTargetClass">
            <value>true</value>
        </property>
        <property name="transactionManager">
            <ref bean="transactionManager"/>
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
</bean>
   
<bean id="userInfoDAOProxy" parent="baseDAOProxy">
        <property name="target">
            <ref bean="userInfoDAO"/>
        </property>
</bean>

  结论:采用Spring 1.x配置事务要额外配置一个代理对象,原来Bean的获取方式也要修改,因此,也是一种“侵入式”的解决方案,虽然没有侵入到Bean程序代码中。
2) 使用Spring 2.x 的aop 和tx 声明式配置进行事务管理
A. 在applicationContext.xml中添加aop和tx名称空间

 

Xml代码 <beans xmlns="http://www.springframework.org/schema/beans
    xmlns:aop="http://www.springframework.org/schema/aop
    xmlns:tx="http://www.springframework.org/schema/tx
    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-2.0.xsd 
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-2.0.xsd 
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> 
 
 ………… 
</beans> 
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    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-2.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

 …………
</beans>

   B. 在applicationContext.xml中声明事务管理器,注入sessionFactory属性

 

Xml代码 <bean id="transactionManager" 
class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
        <property name="sessionFactory"> 
            <ref local="sessionFactory" /> 
        </property> 
</bean> 
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref local="sessionFactory" />
        </property>
</bean>
C. 通过 <tx:advice>定义事务通知

 

Xml代码 <tx:advice id="txAdvice" transaction-manager="transactionManager"> 
        <tx:attributes> 
            <tx:method name="add*" propagation="REQUIRED"/> 
            <tx:method name="del*" propagation="REQUIRED"/> 
            <tx:method name="update*" propagation="REQUIRED"/> 
            <tx:method name="do*" propagation="REQUIRED"/> 
            <tx:method name="*" propagation="SUPPORTS" read-only="true"/> 
        </tx:attributes> 
</tx:advice> 
<tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="add*" propagation="REQUIRED"/>
            <tx:method name="del*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="do*" propagation="REQUIRED"/>
            <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>
</tx:advice>

   D. 将事务通知advice和切面pointcut组合起来

 

Xml代码 <aop:config> 
        <aop:pointcut id="daoMethods" expression="execution(* cn.qdqn.ssh.dao.*.*(..))"/> 
        <aop:advisor advice-ref="txAdvice" pointcut-ref="daoMethods"/> 
</aop:config> 
<aop:config>
        <aop:pointcut id="daoMethods" expression="execution(* cn.qdqn.ssh.dao.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="daoMethods"/>
</aop:config>
E. 两种应用测试:
a) 对于Java Application,直接获取DAO Bean,进行数据库操作

 

Java代码 ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); 
UserInfoDAO dao=(UserInfoDAO)ctx.getBean("userInfoDAO"); 
UserInfo user=new UserInfo(); 
user.setUserName("比尔盖茨"); 
user.setUserPwd("windows"); 
dao.save(user); 
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
UserInfoDAO dao=(UserInfoDAO)ctx.getBean("userInfoDAO");
UserInfo user=new UserInfo();
user.setUserName("比尔盖茨");
user.setUserPwd("windows");
dao.save(user);

  问题:运行程序会报以下异常

 

Exception 代码 Exception in thread "main" java.lang.ClassCastException: $Proxy1 
                 at cn.qdqn.ssh.test.AddUserInfo.main(AddUserInfo.java:18) 
Exception in thread "main" java.lang.ClassCastException: $Proxy1
                 at cn.qdqn.ssh.test.AddUserInfo.main(AddUserInfo.java:18)

  解决方法:此时唯有JDK 基于接口的代理将起作用,因此每个BO或DAO类必须要有对应的Interface,可以使用MyEclipse的重构功能生成BO或DAO类的接口定义,将获取的BO或DAO Bean放在相应接口对象的引用中即可。代码修改如下:

Java代码  ApplicationContext ctx= 
new ClassPathXmlApplicationContext("applicationContext.xml"); 
IUserInfoDAO dao=(IUserInfoDAO)ctx.getBean("userInfoDAO"); 
UserInfo user=new UserInfo(); 
user.setUserName("比尔盖茨"); 
user.setUserPwd("windows"); 
dao.save(user); 
 ApplicationContext ctx=
new ClassPathXmlApplicationContext("applicationContext.xml");
IUserInfoDAO dao=(IUserInfoDAO)ctx.getBean("userInfoDAO");
UserInfo user=new UserInfo();
user.setUserName("比尔盖茨");
user.setUserPwd("windows");
dao.save(user);    

        b) 对于Web Application,在Struts Action定义BO或DAO,通过Spring在action-servlet.xml中进行注入

Xml代码  public class AddAction extends Action { 
    private UserInfoDAO userInfoDAO; 
    public UserInfoDAO getUserInfoDAO() { 
        return userInfoDAO; 
    } 
    public void setUserInfoDAO(UserInfoDAO userInfoDAO) { 
        this.userInfoDAO = userInfoDAO; 
    } 
 
………… 

 public class AddAction extends Action {
    private UserInfoDAO userInfoDAO;
    public UserInfoDAO getUserInfoDAO() {
        return userInfoDAO;
    }
    public void setUserInfoDAO(UserInfoDAO userInfoDAO) {
        this.userInfoDAO = userInfoDAO;
    }

…………
}Xml代码 <bean name="/add" class="cn.qdqn.ssh.struts.action.AddAction"> 
      <property name="userInfoDAO"> 
        <ref bean="userInfoDAO"/> 
      </property> 
</bean> 
<bean name="/add" class="cn.qdqn.ssh.struts.action.AddAction">
      <property name="userInfoDAO">
        <ref bean="userInfoDAO"/>
      </property>
</bean>

        问题:启动Tomcat会报以下异常

 

Exception 代码 org.springframework.beans.factory.BeanCreationException: Error creating bean with name '/add' defined in ServletContext resource [/WEB-INF/action-servlet.xml]: Error setting property values; nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are: 
PropertyAccessException 1: org.springframework.beans.TypeMismatchException: Failed to convert property value of type [$Proxy1] to required type [cn.qdqn.ssh.dao.UserInfoDAO] for property 'userInfoDAO'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [$Proxy1] to required type [cn.qdqn.ssh.dao.UserInfoDAO] for property 'userInfoDAO': no matching editors or conversion strategy found 
Caused by:  
org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessException details (1) are: 
PropertyAccessException 1: 
org.springframework.beans.TypeMismatchException: Failed to convert property value of type [$Proxy1] to required type [cn.qdqn.ssh.dao.UserInfoDAO] for property 'userInfoDAO'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [$Proxy1] to required type [cn.qdqn.ssh.dao.UserInfoDAO] for property 'userInfoDAO': no matching editors or conversion strategy found 
 
 ………… 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name '/add' defined in ServletContext resource [/WEB-INF/action-servlet.xml]: Error setting property values; nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
PropertyAccessException 1: org.springframework.beans.TypeMismatchException: Failed to convert property value of type [$Proxy1] to required type [cn.qdqn.ssh.dao.UserInfoDAO] for property 'userInfoDAO'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [$Proxy1] to required type [cn.qdqn.ssh.dao.UserInfoDAO] for property 'userInfoDAO': no matching editors or conversion strategy found
Caused by:
org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessException details (1) are:
PropertyAccessException 1:
org.springframework.beans.TypeMismatchException: Failed to convert property value of type [$Proxy1] to required type [cn.qdqn.ssh.dao.UserInfoDAO] for property 'userInfoDAO'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [$Proxy1] to required type [cn.qdqn.ssh.dao.UserInfoDAO] for property 'userInfoDAO': no matching editors or conversion strategy found

 …………

        解决方法:同Java Application所遇错误相类似,只需将Struts Action定义的等待被注入的BO或DAO替换为其相应的Interface形式即可纠正该错误。如下代码:

 

Java代码 public class AddAction extends Action { 
    private IUserInfoDAO userInfoDAO; 
    public IUserInfoDAO getUserInfoDAO() { 
        return userInfoDAO; 
    } 
    public void setUserInfoDAO(IUserInfoDAO userInfoDAO) { 
        this.userInfoDAO = userInfoDAO; 
    } 
 
………… 

public class AddAction extends Action {
    private IUserInfoDAO userInfoDAO;
    public IUserInfoDAO getUserInfoDAO() {
        return userInfoDAO;
    }
    public void setUserInfoDAO(IUserInfoDAO userInfoDAO) {
        this.userInfoDAO = userInfoDAO;
    }

…………
}

3) 【最佳方案】使用Spring 2.x 的@Transactional标注进行事务管理
A. 在BO或DAO类中添加事务标注@Transactional

 

Java代码 import org.springframework.transaction.annotation.Transactional; 
 
@Transactional 
public class UserInfoDAO extends HibernateDaoSupport { 
    private static final Log log = LogFactory.getLog(UserInfoDAO.class); 
    public static final String USER_NAME = "userName"; 
    public static final String USER_PWD = "userPwd"; 
    public void save(UserInfo transientInstance) { 
        log.debug("saving UserInfo instance"); 
        try { 
            getHibernateTemplate().save(transientInstance); 
            log.debug("save successful"); 
        } catch (RuntimeException re) { 
            log.error("save failed", re); 
            throw re; 
        } 
    } 
部 分代码省略…… 

import org.springframework.transaction.annotation.Transactional;

@Transactional
public class UserInfoDAO extends HibernateDaoSupport {
    private static final Log log = LogFactory.getLog(UserInfoDAO.class);
    public static final String USER_NAME = "userName";
    public static final String USER_PWD = "userPwd";
    public void save(UserInfo transientInstance) {
        log.debug("saving UserInfo instance");
        try {
            getHibernateTemplate().save(transientInstance);
            log.debug("save successful");
        } catch (RuntimeException re) {
            log.error("save failed", re);
            throw re;
        }
    }
部分代码省略……
}

   B. 在applicationContext.xml中添加transactionManager和 <tx:annotation-driven>

 

Xml代码 <bean id="transactionManager" 
            class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
        <property name="sessionFactory"> 
            <ref local="sessionFactory" /> 
        </property> 
</bean> 
<tx:annotation-driven transaction-manager="transactionManager"  
                                       proxy-target-class="true"/> 
<bean id="transactionManager"
            class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref local="sessionFactory" />
        </property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"
                                       proxy-target-class="true"/>  注意:proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。如果proxy-target-class 属性值被设置为true,那么基于类的代理将起作用(这时需要cglib库)。如果proxy-target-class属值被设置为false或者这个 属性被省略,那么标准的JDK 基于接口的代理将起作用。 
C. 测试运行,一切正常

 

Java代码 ApplicationContext ctx= 
new ClassPathXmlApplicationContext("applicationContext.xml"); 
UserInfoDAO dao=(UserInfoDAO)ctx.getBean("userInfoDAOProxy"); 
UserInfo user=new UserInfo(); 
user.setUserName("比尔盖茨"); 
user.setUserPwd("windows"); 
dao.save(user); 
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值