• 重构项目使用Spring+Hibernate+HibernateAnnotation+GenericDao技术


    本文首先要讲述我重构原先课程大作业做过的一个汽车4S店业务管理系统的过程。

    2011-12-25

      记录将原有项目从Spring+Hibernate的框架改造成Spring+Hibernate+HibernateAnnotation+GenericDao的过程。

      首先,是要尽量做到使系统的数据库访问层能够通用,以后做类似的基于SSH框架的项目可用重用我们现在的数据访问层的代码。比如用户信息数据访问层UserDao的实现我们可以参见我前一篇博客:数据库访问层中使用GenericDao和HibernateDaoSupport。其实,如果为了简洁方便,在需要访问数据库的时候,我们可以不写接口UserDao和接口实现UserDaoImpl,而是直接通过如下代码来实现UserDaoImpl的功能:

      GenericDaoImplHibernate<User> userDaoImpl=new GenericDaoImplHibernate<User>();
    List<User> list=userDaoImpl.findAll(User.class);

    但是为了使得我们的数据库访问层扩展性更好,我们还是使用了UserDao和UserDaoImpl这两个类。在后面我们会见到扩展性的优势。

      其次,是关于Hibernate-Annotation的使用问题,原先是通过pojo文件+.hbm文件进行数据库映射,现在发现使用.hbm文件过于繁杂,考虑使用带标注的pojo来实现数据库映射。具体方法可以参见我前面写过的一篇博客:使用Hibernate-tools中的hbm2java和hbm2ddl根据hbm文件自动生成pojo和数据库脚本。在这篇文章中介绍了在已知.hbm文件的情况下,如何生成带标注的pojo文件。

    2011-12-26

      然后是对各个技术进行分析,原先系统使用了Spring-MVC中的一些内容,比如url拦截,session注入等功能。那么我现在考虑不使用Spring提供的sessionFactory注入,而是在具体的dao中使用自己定义的HibernateSessionFactory来实例化sessionFactory。这样也是可以实现的。(之所以不使用Spring提供的sessionFactory注入是为了调试方便,因为如果要使用Spring的依赖注入,则必须启动tomcat服务器进行调试,而不能直接通过写java demo类来调试方法。

      首先我们来看spring配置文件的变更,原来是通过在spring中注册.hbm文件来实现数据库的映射,配置方法如下:

    View Code
    <beans>
        <!-- 数据库连接配置 -->
        <bean id="dataSource"
            class="org.springframework.jdbc.datasource.DriverManagerDataSource"
            destroy-method="close">
            <property name="driverClassName" value="com.mysql.jdbc.Driver" />
            <property name="url"
                value="jdbc:mysql://localhost:3306/ssh1?useUnicode=true&amp;characterEncoding=UTF-8" />
            <property name="username" value="root" />
            <property name="password" value="123456" />
        </bean>
    
        <bean id="sessionFactory"
            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
            <property name="dataSource">
                <ref bean="dataSource" />
            </property>
            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                    <prop key="hibernate.show_sql">true</prop>
                    <prop key="hibernate.max_fetch_depth">5</prop>
                    <prop key="hibernate.use_outer_join">false</prop>
                    <prop key="hibernate.jdbc.batch_size">50</prop>
                </props>
            </property>
            <property name="mappingResources">
                <list>
                    <value>com/sjtu/erp/ssh/pojo/Car.hbm.xml</value>
                    <value>com/sjtu/erp/ssh/pojo/User.hbm.xml</value>
                </list>
            </property>
        </bean>
    
        <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
            <property name="sessionFactory">
                <ref bean="sessionFactory" />
            </property>
        </bean>
    </beans>

      现在我们使用了Hibernate-Annotation,因此不再需要管理.hbm文件,不过需要一个单独的hibernate.cfg.xml来进行数据库映射。spring配置内如容下:

    View Code
    <!--第一种 =====hibernate cfg配置文件+AnnotationConfiguration===== --> 
        <bean id="sessionFactory"
            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
            <property name="dataSource">
                <ref bean="dataSource" />
            </property>
            <property name="configurationClass">  
                <value>org.hibernate.cfg.AnnotationConfiguration</value>  
            </property>  
            <property name="configLocation">  
                <value>classpath:hibernate.cfg.xml</value>  
            </property>      
        </bean>

      注意到在上述配置中有一个 <property name="configurationClass">,这个属性指定的类就是org.hibernate.cfg.AnnotationConfiguration。这表示使用hibernate-annotation。还有 <property name="configLocation">指定的地址是:classpath:hibernate.cfg.xml。这表示要将hibernate.cfg.xml文件放在src的根目录下。eclipse项目中,classpath就是src目录,当将项目发布到服务器以后,hibernate.cfg.xml会被发布到apache-tomcat\webapps\carmis\WEB-INF\classes这个目录下。接下来是hibernate.cfg.xml配置文件的内容,内容如下所示:

    View Code
    <?xml version='1.0' encoding='utf-8'?>
    <!DOCTYPE hibernate-configuration PUBLIC 
        "-//Hibernate/Hibernate Configuration DTD//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
        <session-factory>   
            <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
            <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
            <property name="connection.username">root</property>
            <property name="connection.password">123456</property>
            <property name="connection.url">jdbc:mysql://localhost:3306/4scarms</property>
            <property name="show_sql">true</property>
            <property name="connection.autocommit"> true </property> 
    
            <mapping class="edu.sjtu.ist.ssh.pojo.Car" />
            <mapping class="edu.sjtu.ist.ssh.pojo.User" />
        </session-factory>
    </hibernate-configuration>

      对于hibernate.cfg.xml的结构与内容我们都已经很熟悉了,这里就不再赘述。仔细查看这个配置文件,我们会发现<mapping class>对应的属性是Pojo类,而之前我们在spring中配置的是 <property name="mappingResources">,他所对应的是.hbm文件。

      上述的变更都是为了适应hibernate-annotation,也就是不再使用.hbm文件进行数据库映射,而使用带注释的Pojo进行数据库映射作出的配置文件变更。下面的变更是为了不使用sessionFactoryd的IOC,而是通过在DaoImpl中手动知道sessionFactory。下面先来看一下配置文件的对比:

    View Code
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
    <beans>
        
        <!--userDaoImpl使用了GenericDao-->
        <bean id="userDaoImpl" class="edu.sjtu.ist.ssh.dao.impl.UserDaoImpl">
            <property name="sessionFactory">
                <ref bean="sessionFactory" />
            </property>
        </bean>
        
        <bean id="carDaoImpl" class="edu.sjtu.ist.ssh.dao.impl.CarDaoImpl">
            <!--
            这里注入sessionFactory相当于是在CarDaoImpl实例化对象的时候调用
            this.setSessionFactory(sessionFactory);
            但是现在我们已经在CarDaoImpl实现了,所以不需要注入。
            <property name="sessionFactory">
                <ref bean="sessionFactory" />
            </property>
            -->
        </bean>
    </beans>

    ——————————————————————————————

    PS:2012-5-20反射的应用

      在使用spring的时候我们经常会提到依赖注入的问题,这里所谓的依赖注入就是并不在类中显示创建对象,比如类似:UserDaoImpl userDaoImpl=new UserDaoImpl(); 这样的显示创建userDaoImpl实例,而是通过<bean id="userDaoImpl" class="edu.sjtu.ist.ssh.dao.impl.UserDaoImpl">这样的配置文件来创建一个userDaoImpl对象实例。这里用到了java的反正机制,通过一个字符串描述具体的类型就可以创建一个userDaoImpl对象。在具体使用userDaoImpl对象的时候,相当于调用了UserDaoImpl userDaoImpl=Class.forName(edu.sjtu.ist.ssh.dao.impl.UserDaoImpl).getInstance(); 这样的方法。

      至于其中的property属性:<property name="sessionFactory"> <ref bean="sessionFactory" /> </property> 相当于是在构造函数中设置了一定的参数。如果我们不设置property属性那么就需要在UserDaoImpl类中显示声明那些必须进行初始化的参数。比如上述的sessionFactory这个属性。这个sessionFactory就是需要注入的参数

    ——————————————————————————————

      spring的一大特点就是IOC,IOC的基本概念是:不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务,容器负责将这些联系在一起。现在就是在配置文件中,我们指定组件userDaoImpl是由类edu.sjtu.ist.ssh.dao.impl.UserDaoImpl实例化而来,并且sessionFactory是需要注入的对象实例。而carDaoImpl中则没有需要注入的对象实例,这是因为我们在CarDaoImpl这个类中进行了手工注入,代码如下所示:

    View Code
    package edu.sjtu.ist.ssh.dao.impl;
    
    import edu.sjtu.ist.ssh.dao.CarDao;
    import edu.sjtu.ist.ssh.genericdao.GenericDaoImplHibernate;
    import edu.sjtu.ist.ssh.local.genericdao.HibernateSessionFactory;
    import edu.sjtu.ist.ssh.pojo.Car;
    
    public class CarDaoImpl extends GenericDaoImplHibernate<Car> implements CarDao {
        /**
         * 通过spring构造CarDaoImpl实例的时候,    public CarDaoImpl(){}构造函数被调用,
         * 指定了sessionFactory
         */
        public CarDaoImpl()
        {
            this.setSessionFactory(HibernateSessionFactory.getSessionFactory());
        }
    }

      而HibernateSessionFactory的定义则如下述代码所示:

    View Code
    package edu.sjtu.ist.ssh.local.genericdao;
    
    import org.hibernate.HibernateException;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.AnnotationConfiguration;
    import org.hibernate.cfg.Configuration;
    
    public class HibernateSessionFactory {
    
        private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
        private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
        private static AnnotationConfiguration acfg = new AnnotationConfiguration(); 
        private static SessionFactory sessionFactory;
        private static String configFile = CONFIG_FILE_LOCATION;
    
        static {
            try {
                acfg.configure(configFile);
                sessionFactory = acfg.buildSessionFactory();
            } catch (Exception e) {
                System.err
                        .println("%%%% Error Creating SessionFactory %%%%");
                e.printStackTrace();
            }
        }
        private HibernateSessionFactory() {
        }
    
        public static Session getSession() throws HibernateException {
            Session session = (Session) threadLocal.get();
            if (session == null || !session.isOpen()) {
                if (sessionFactory == null) {
                    rebuildSessionFactory();
                }
                session = (sessionFactory != null) ? sessionFactory.openSession()
                        : null;
                threadLocal.set(session);
            }
            return session;
        }
    
        public static void rebuildSessionFactory() {
            try {
                acfg.configure(configFile);
                sessionFactory = acfg.buildSessionFactory();  
            } catch (Exception e) {
                System.err
                        .println("%%%% Error Creating SessionFactory %%%%");
                e.printStackTrace();
            }
        }
    
        public static void closeSession() throws HibernateException {
            Session session = (Session) threadLocal.get();
            threadLocal.set(null);
    
            if (session != null) {
                session.close();
            }
        }
    
        public static SessionFactory getSessionFactory() {
            return sessionFactory;
        }
    
        public static void setConfigFile(String configFile) {
            HibernateSessionFactory.configFile = configFile;
            sessionFactory = null;
        }
    
        public static AnnotationConfiguration getAnnotationConfiguration() {
            return acfg;
        }
    
    }

      这里HibernateSessionFactory所起到的功能就是类似于spring配置文件中的<bean id="sessionFactory">。通过上述的方法,我们就不再需要在配置文件中注入sessionFactory这个实例。这样做的一个好处是我们能够在不启动tomcat服务器的情况下,就能使用CarDaoImpl这个类,能够更好的测试他们。如果要使用spring的依赖注入这一特性注入sessionFactory这个实例,那么必须启动tomcat,然后才能使用CarDaoImpl这个类。

      还有就是不使用spring的action,而是使用stucts来作为项目MVC架构中的Controller。即真正实现我们的SSH架构,而不是我们当前的SH架构。

    2011:12-27--12-28

    再接着实现日志管理功能。我们可以使用log4j,也可以让common-logging结合log4j来使用,还有可以使用sflog4j等等日志管理功能。更是可以自己对log4j进行封装,自定义日志管理功能。当前比较推荐的使用common-logging和log4j结合使用的模式。因为common-logging和log4j都是开源项目,可是使用GreenUML来查看这两个项目的整体架构,可以从中学习到一些知识,比如设计模式中的单例模式,工厂模式的使用等等。关于log这一部分的内容,可以参考我的一篇博客:log4j+commons-logging结合使用,里面详解介绍了log的使用方法,并且根据log的不同等级往不同地址存储log。

    2012-1-10

    1)使用消息托送的方式实现看板,消息中间件用ActiveMQ。

    2)实现数据库的备份还原,不得单单只是按钮,还需要一个操作界面,能够选择具体备份还原哪一个数据库。刚开始需要插入的信息是数据的基本信息,比如connecturl,databasename,username,password等等,后期就是对这个数据库进行操作。

    3)实现文件的上传下载功能,还有一个上传下载的功能界面用户管理上传的文件。比如删除功能。

    2012-2-19

    一个多月的寒假,玩到罪恶感回来,开始新的学期,fighting!

    2012-10-29

    那么IOC的好处是什么呢?

    在以前如果要使用一个类B的方法,那么就必须在当前类A下new一个B类的实例,这样间接会造成A与B的耦合,而如果使用IOC,那么就不需要使用new来创建对象了,而是通过配置文件来创建对象,负责这一任务的是spring 容器。这样相当于是解耦工作,当我们业务发生变成的时候,就不再需要修改原有代码,而只需要修改配置文件即可。

    比如我们要访问数据库都会使用到DAO层,而DAO层也是根据特定数据库来写的,加入原先使用的是SQL Server,那么现在加入要使用Oracle了,如果没有使用IOC,那么就必须在原有代码下修改。而加入使用了IOC,那么我们只需要修改配置文件,将DAO指向新的数据库访问层即可。不过这些需要具体Oracle的DAO层。但是这样没有修改原有的代码。代码增加远远好于代码变更。

  • 相关阅读:
    重构二叉树
    LeetCode-Construct Binary Tree from Preorder and Inorder Traversal
    二叉平衡树
    二叉树的三种递归与非递归遍历算法
    Jump Game
    Ubuntu中安装最新 Node.js 和 npm
    ORACLE查看并修改最大连接数
    设计模式之工厂模式
    设计模式之单例模式
    设计模式之模板方法模式
  • 原文地址:https://www.cnblogs.com/xwdreamer/p/2302225.html
Copyright © 2020-2023  润新知