美文网首页我爱编程程序员
04_Spring-SSH框架整合

04_Spring-SSH框架整合

作者: 明天你好向前奔跑 | 来源:发表于2017-07-18 22:36 被阅读0次

    SSH框架整合(XML方式)

    一、搭建环境

    新建web工程,准备搭建环境

    1. Struts2环境搭建

    1.1 导包
    1. 导入Struts2的必需jar包(通过模板的jar包导入)
        其中log4j的两个jar包不导,因为我们使用的是log4j.properties的配置文件,在Spring导入时使用log4j 1.x的版本.
    
    2. 导入Sturts2与Spring的整合包struts2-spring-plugin-2.3.32.jar
    
    3.导入Struts2的jar包如下,共12个包.(Spring处导入log4j的日志包)
    
    img54.png
    1.2 Sturts2的配置文件
    1. 修改web.xml配置Struts2的前端控制器
        <!-- Struts2前端控制器 -->
        <filter>
            <filter-name>struts2</filter-name>
            <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    
    2. 配置Sturts2的核心配置文件struts2.xml到src(从模板中复制,删除到最简单的配置)
        如果要添加配置提示,根据DTD文件添加到Xml Catalog中
            
        1. 关闭开发者模式(常量设置从/org/apache/struts2/default.properties中查找)
            缺点:开发者模式不能处理ajax的异常
            但我们需要自动加载配置文件的功能,因此要开启自动加载配置文件的开关
    
        2. 修改Sturts2的前端样式为simple
        
        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE struts PUBLIC
            "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
            "http://struts.apache.org/dtds/struts-2.3.dtd">
        <struts>
        
            <!-- 关闭开发者模式 -->
            <!-- <constant name="struts.devMode" value="true" /> -->
            <constant name="struts.configuration.xml.reload" value="true" />
        
            <!-- 使用简单样式 -->
            <constant name="struts.ui.theme" value="simple" />
        
            <!-- 自定义包,配置Action -->
            <package name="default" namespace="/" extends="struts-default">
            </package>
        </struts>
    
    
    3. 拷贝log4j.properties日志配置文件到src目录
        ### direct log messages to stdout ###
        log4j.appender.stdout=org.apache.log4j.ConsoleAppender
        log4j.appender.stdout.Target=System.err
        log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
        log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
        
        ### direct messages to file mylog.log ###
        log4j.appender.file=org.apache.log4j.FileAppender
        log4j.appender.file.File=d:\\mylog.log
        log4j.appender.file.layout=org.apache.log4j.PatternLayout
        log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
        
        ### set log levels - for more verbose logging change 'info' to 'debug' ###
        log4j.rootLogger=info, stdout,file
    
    4. Sturts2环境搭建完成
    

    2. Spring4环境搭建

    2.1 导包
    1. Spring必需包(4+2) : 
        beans,context,core,expression.+ 两个日志jar包:apache-commen logging 1.x.jar与log4j.jar
    
    2. Spring在web中使用的jar包: spring-web-4.2.4.RELEASE.jar
    
    3. Spring操作数据库相关jar包: 
        spring-jdbc-4.2.4.RELEASE.jar   spring-tx-4.2.4.RELEASE.jar(事务包,与jdbc包耦合)
    
    4. 事务管理的jar包:(依赖AOP)
        tx  jdbc 
        aop的4个jar包 : aop联盟,Aspectj,Spring整合它们的两个jar包
    
    5. Spring整合ORM框架的jar包
        spring-orm-4.2.4.RELEASE.jar
    
    6. Spring测试包:
        spring-test-4.2.4.RELEASE.jar
    
    这里共15个jar包.
    与Struts2的jar包总共27个jar包。
    
    2.2 Spring的核心监听器

    以前获取ApplicationContext(Spring容器)都是直接获取,每次都要根据配置文件重新创建一个Spring容器.

    在创建Spring容器同时,需要对容器中对象初始化。而每次初始化容器的时候,都创建了新的容器对象,消耗了资源,降低了性能。

    解决思路 : 保证Spring容器只有一个

    解决方案:将Spring容器绑定到Web Servlet容器上,让Web容器来管理Spring容器的创建和销毁。

    编写一个ServletContextListener监听器,在监听ServletContext到创建的时候,创建Spring容器,
    并将其放到ServletContext的属性中保存(setAttribute(Spring容器名字,Spring容器对象) )。 
    
    我们无需手动创建该监听器,因为Spring提供了一个叫ContextLoaderListener的监听器,它位于spring-web.jar中。
    

    web.xml中配置Spring的核心监听器,将Spring容器的创建绑定到ServletContext

    Spring的核心监听器必须写在Struts2的前端控制前,才能对ServletContext的创建起到监听作用。
    
    <!-- Spring的核心监听器 -->
    <listener>
        <!-- Spring提供的ContextLoaderListener监听器 -->
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 全局参数 -->
    <context-param>
        <!-- 默认加载的配置文件在web-inf里的applicationContext.xml,因此需要修改 -->
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    
    2.3 Spring的核心配置文件applicationContext.xml

    复制核心配置文件到src目录下:

    头约束包括:beans,context,tx,aop
    -----------------------------------------------------------------------------
    
    <?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"
        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.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    </beans>
    
    2.4 日志配置文件(Struts2搭建已经完成)

    3 Hibernate5环境搭建

    3.1 导包
    1. 导入Hibernate5必需required文件夹中的jar包(9-1)
        其中,javasist的版本与Struts2中的javasist版本冲突了,留下高版本的jar包。
    
    2. 导入数据库驱动 1
        mysql-connector-java-5.1.18-bin.jar
    
    3. 导入连接池(数据源)C3P0的jar包 1
        这里不用Hibernate提供的c3p0的jar包,Hibernate提供的3个c3p0的jar包全整合只需要一个.
        我这里就从Spring提供的c3p0拷贝一个jar包过来。
        com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
    
    Hibernate导入jar包10个。
    
    3.2 Hibernate核心配置文件hibernate.cfg.xml

    拷贝Hibernate的核心配置文件到src目录下

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- 导入Hibernate核心配置的DTD约束 -->
    <!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    
    <hibernate-configuration>
        <session-factory>
            <!--1. 基本配置 -->
            <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
            <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_day02</property>
            <property name="hibernate.connection.username">root</property>
            <property name="hibernate.connection.password">root</property>
    
            <!--2. 与本地线程绑定 -->
            <property name="hibernate.current_session_context_class">thread</property>
    
            <!--3. Hibernate的属性 -->
            <!--Hibernate的方言配置,实现了跨数据库  -->
            <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
    
            <!-- 显示sql语句 -->
            <property name="hibernate.show_sql">true</property>
            <property name="hibernate.format_sql">true</property>
    
            <!-- Hibernate表格的创建方式 -->
            <property name="hibernate.hbm2ddl.auto">update</property>
    
            <!-- 
                设置隔离级别:
                    hibernate.connection.isolation = 4
                    1-Read uncommitted isolation
                    2-Read committed isolation
                    4-Repeatable read isolation
                    8-Serializable isolation 
            -->
            <property name="hibernate.connection.isolation">4</property>
    
            <!-- C3P0的供应商 -->
            <property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
            <!-- 最小连接 -->
            <property name="hibernate.c3p0.min_size">5</property>
            <!-- 最大连接数 -->
            <property name="hibernate.c3p0.max_size">20</property>
            <!-- 连接超时时长 -->
            <property name="hibernate.c3p0.timeout">120</property>
            <!-- 每120秒检查空闲连接 -->
            <property name="hibernate.c3p0.idle_test_period">120</property>
            <!-- 最大statments数量 -->
            <property name="hibernate.c3p0.max_statements">120</property>
            <!-- 连接用完后,每次增加的连接数 -->
            <property name="hibernate.c3p0.acquire_increment">2</property>
            <!-- 每次都验证连接是否可用 -->
            <property name="hibernate.c3p0.validate">false</property>
    
            <!--4. 加载映射文件 -->
            <mapping resource="com/itdream/domain/Customer.hbm.xml" />
        </session-factory>
    </hibernate-configuration>
    

    到这里,SSH三个框架的环境基本就搭建完成了,下面去完成SSH框架的互相整合。

    二、 整合Spring与Hibernate5框架

    2.1 首先继续完成Hibernate5的环境搭建

    根据需求完成Hibernate(ORM)框架的搭建。

    例: 持久化类:Product. 数据库表:product. 建立持久化类与数据库表的映射Product.hbm.xml

    //持久化类Product
    public class Product {
    
        private Integer pid;
        private String pname;
        private Double price;
    
        public Integer getPid() {
            return pid;
        }
    
        public void setPid(Integer pid) {
            this.pid = pid;
        }
    
        public String getPname() {
            return pname;
        }
    
        public void setPname(String pname) {
            this.pname = pname;
        }
    
        public Double getPrice() {
            return price;
        }
    
        public void setPrice(Double price) {
            this.price = price;
        }
    
        @Override
        public String toString() {
            return "Product [pid=" + pid + ", pname=" + pname + ", price=" + price + "]";
        }
    }
    
    ---------------------------------------------------------------------------
    
    根据Product持久化类创建映射关系配置文件Product.hbm.xml:
    <?xml version="1.0" encoding="UTF-8"?>
    <!-- 引入DTD约束 -->
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        
     <hibernate-mapping>
        <!-- 建立持久化类与表的映射关系 -->
        <class name="com.itdream.ssh.domain.Product" table="product">
            <!-- 建立持久化类标OID与数据库主键的映射,name与column相同可省略column -->
            <id name="pid">
                <generator class="native"/>
            </id>
            
            <!-- 配置持久化类普通属性与数据库字段的映射 -->
            <property name="pname"/>
            <property name="price"/>
        </class>
     </hibernate-mapping>
    
    -----------------------------------------------------------------------------
    
    在Hibernate.cfg.xml中加载该映射文件:
        <mapping resource="com/itdream/ssh/domain/Product.hbm.xml" />
    
    2.2 Spring与Hibernate框架的整合

    Spring与Hibernate框架的整合有两种方式:完全整合【推荐】,半整合

    我们的原则是能交给Spring托管的都给Spring框架管理,因此这里就不详解半整合

    思想:将Hibernate中SessionFactory对象,由Spring管理。
    通过 spring-orm包 提供 LocalSessionFactoryBean 实现。
    

    Spring与Hibernate的完全整合:

    优点:将hibernate参数配置到spring文件,没有hibernate配置文件 !!!SessionFactory由Spring管理.

    根据Hibernate.cfg.xml: 需要三个方面的配置 (数据源配置、 常用属性配置、 hbm映射加载 )

    1. 因此在applicationContext.xml中先注册c3p0数据源的bean:
    
    从applicationContext中抽取数据源的变量,便于维护:
    db.properties:
        jdbc.dataSourceClass=com.mchange.v2.c3p0.ComboPooledDataSource
        jdbc.driverClassName=com.mysql.jdbc.Driver
        jdbc.url=jdbc:mysql://localhost:3306/spring
        jdbc.username=root
        jdbc.password=root
    
    
        <!-- 引入外部配置文件,下面使用${key}取值 -->
        <context:property-placeholder location="classpath:db.properties"/>
        
        <!-- 注册数据源 -->
        <bean id="dataSource" class="${jdbc.dataSourceClass}">
            <property name="driverClass" value="${jdbc.driverClassName}"/>
            <property name="jdbcUrl" value="${jdbc.url}"/>
            <property name="user" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </bean>
    
    
    2. 将hibernate.cfg.xml的参数完全配置到applicationContext.xml中,由Spring管理SessionFactory.这样Spring容器创建的时候,会创建注入了数据源的SessionFacotory.
    
    **这里注意导入LocalSessionFactoryBean的时候,不要导错版本的全包名,选择Hibernate5**
    
        <!-- Spring管理SessionFactory -->
        <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
            <!-- 1.数据源 -->
            <property name="dataSource" ref="dataSource"/>
            
            <!-- 2.Hibernate属性 -->
            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                    <prop key="hibernate.show_sql">true</prop>
                    <prop key="hibernate.format_sql">true</prop>
                    <prop key="hibernate.hbm2ddl.auto">update</prop>
                </props>
            </property>
            
            <!-- 3.Hibernate映射文件 -->
            <property name="mappingResources">
                <list>
                    <value>com/itdream/ssh/domain/Product.hbm.xml</value>
                </list>
            </property>
        </bean>
    
    修改hiberante.cfg.xml的名称为hibernate.cfg.bak.xml表示已经不用,或直接删除。
    
    这里将hibernate.cfg.xml的参数全都配置到Spring中了,已经完成了完全整合。
    
    测试是否整合成功:启动服务器,观察指定的数据库ssh中是否自动建表product
    

    2.3 使用HibernateTemplate完成数据库操作

    上面Spring与Hibernate的完全整合基本完成(还差事务管理的配置,这里根据实际操作待会设置)。

    Spring提供了一个HibernateTemplate模板类大大简化了对数据库的操作.

    为了简化HibernateTemplate的操作,Spring又提供了HibernateDaoSupport类

    在开发时,只需要让DAO层继承HibernateDaoSupport,Spring容器创建的时候,会创建注入了数据源的SessionFacotory。在配置文件中,将SessionFactory注入到DAO中,会调用父类的setter方法,它的setter方法内部会根据这个SessionFactory生成一个HibernateTemplate的对象,子类DAO可以直接获取使用。

    img55.png
    ProductDAO:
    
    //dao层,继承HibernateDaoSupport简化操作
    public class ProductDAO extends HibernateDaoSupport {
    
        // 添加商品
        public void save(Product product) {
            getHibernateTemplate().save(product);
        }
    
        // 删除商品
        public void delete(Product product) {
            getHibernateTemplate().delete(product);
        }
    
        // 修改商品信息(底层根据id修改)
        public void update(Product product) {
            getHibernateTemplate().update(product);
        }
    
        // 查询单个商品
        public Product findByID(Integer pid) {
            // 方式一:
            return getHibernateTemplate().get(Product.class, pid);
            // 方式二:(使用时才发送sql语句)
            // return getHibernateTemplate().load(Product.class, pid);
        }
    
        // 查询所有商品
        public List<Product> findAll() {
            // 方式一:Spring提供了简单的方式
            return getHibernateTemplate().loadAll(Product.class);
            // 方式二:使用hql查询
            // return getHibernateTemplate().find("from Product");
        }
    
        // ------复杂查询-----------
        // 查询id大于x的商品(HQL语句查询)
        public List<Product> findGreaterthanID(Integer pid) {
            return (List<Product>) getHibernateTemplate().find("form Product where pid > ?", pid);
        }
    
        // 命名查询(sql语句与java代码解耦,写在Product.hbm.xml中)
        // 模糊查询
        public List<Product> findByNamedQuery(String name) {
            return (List<Product>) getHibernateTemplate().findByNamedQuery("Product.findByNameLike", "%" + name + "%");
        }
    
        // 模糊查询(Criteria离线查询)
        public List<Product> findByCriteria(DetachedCriteria criteria) {
            return (List<Product>) getHibernateTemplate().findByCriteria(criteria);
        }
    }
    
    ---------------------------------------------------------------------------
    
    ProductService:
    
    public class ProductService {
    
        // 注入ProductDAO
        private ProductDAO productDAO;
    
        public void setProductDAO(ProductDAO productDAO) {
            this.productDAO = productDAO;
        }
    
        public void saveProduct(Product product) {
            productDAO.save(product);
        }
    
        public void deleteProduct(Product product) {
            productDAO.delete(product);
        }
    
        public void updateProduct(Product product) {
            productDAO.update(product);
        }
    
        public Product findProductByID(Integer pid) {
            return productDAO.findByID(pid);
        }
    
        public List<Product> findAllProduct() {
            return productDAO.findAll();
        }
    
        public List<Product> findProductsGreaterthanID(Integer pid) {
            return productDAO.findGreaterthanID(pid);
        }
    
        // Criteria离线查询
        public List<Product> findProductsByCriteria(DetachedCriteria criteria) {
            return productDAO.findByCriteria(criteria);
        }
    
        // 命名查询
        public List<Product> findByNamedQuery(String name) {
            return productDAO.findByNamedQuery(name);
        }
    }
    
    
    Product.hbm.xml中配置命名查询的语句:
    <!-- 全局hql语句 -->
    <query name="Product.findByNameLike">
        from Product where pname like ?
    </query>
    
    -------------------------------------------------------------------------
    
    在applicationContext.xml中注册ProductDAO和ProductService:
    
    <!-- Spring容器中bean的装配 -->
    <!-- 注册ProductDAO -->
    <bean id="productDAO" class="com.itdream.ssh.dao.ProductDAO">
        <!-- 注入SessionFactory -->
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    
    <!-- 注册ProductService -->
    <bean id="productService" class="com.itdream.ssh.dao.ProductService">
        <!-- 注入ProductDAO -->
        <property name="productDAO" ref="productDAO"/>
    </bean>
    
    ---------------------------------------------------------------------------
    
    为上面ProductService中的所有方法配置事务管理:(基于AOP的Spring写好的增强类)
    <!-- Spring事务管理 -->
    <!-- 注册对应的事务管理器,注入数据源提供连接,这里是session以管理事务 -->
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <!-- 注入数据源 -->
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    
    <!-- 注册事务增强类,注入参数事务管理器,设置事务策略 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="save*" />
            <tx:method name="update*" />
            <tx:method name="delete*" />
            <tx:method name="find*" read-only="true" />
        </tx:attributes>
    </tx:advice>
    
    <!-- 配置切面 -->
    <aop:config>
        <!-- 定义切入点 -->
        <aop:pointcut expression="execution(* com.itdream.ssh.dao.ProductService.*(..))" id="txPointcut"/>
        
        <!-- 配置切入点与通知的关联 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>
    
    ----------------------------------------------------------------------------
    
    测试:
    
    @RunWith(SpringJUnit4ClassRunner.class) // Spring整合Junit
    @ContextConfiguration(locations ={"classpath:applicationContext.xml"}) // 指定配置文件
    public class SpringTest {
    
        // 注入测试bean:ProductService
        @Autowired
        @Qualifier("productService") // 根据bean的id注入
        private ProductService productService;
    
        @Test
        public void saveTest() {
            // 在实体类中提供无参与有参构造
            Product product = new Product(null, "苹果8", 5999D);
            Product product2 = new Product(null, "华为8", 6000D);
            Product product3 = new Product(null, "小米6", 999D);
            Product product4 = new Product(null, "vivo", 1699D);
            Product product5 = new Product(null, "大米1", 100D);
            productService.saveProduct(product);
            productService.saveProduct(product2);
            productService.saveProduct(product3);
            productService.saveProduct(product4);
            productService.saveProduct(product5);
        }
        
        @Test
        public void updateTest() {
            Product product = new Product(1, "大米3", 300D);
            productService.updateProduct(product);
        }
    
        @Test
        public void deleteTest() {
            Product product = new Product();
            product.setPid(4);
            productService.deleteProduct(product);
        }
    
        @Test
        public void findByIDTest() {
            Product product = productService.findProductByID(2);
            System.out.println(product);
        }
    
        @Test
        public void findAllTest() {
            List<Product> allProducts = productService.findAllProduct();
            System.out.println(allProducts);
        }
    
        @Test
        public void findProductsByCriteriaTest() {
            DetachedCriteria criteria = DetachedCriteria.forClass(Product.class);
            criteria.add(Restrictions.like("pname", "%米%"));
            List<Product> productListByCriteria = productService.findProductsByCriteria(criteria);
            System.out.println(productListByCriteria);
        }
    
        // 命名查询测试
        @Test
        public void findProductsByNameQueryTest() {
            List<Product> listByNameQuery = productService.findByNamedQuery("%米%");
            System.out.println(listByNameQuery);
        }
    }
    
    测试成功
    

    上面就完成了Hibernate与Spring整合的所有步骤:

    • 导包
    • Hibernate将SessionFactory交由Spring管理
    • Spring对Service层的方法进行事务管理
    
        applicationContext.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"
            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.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
                http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
        
            <!-- 引入外部配置文件,下面使用${key}取值 -->
            <context:property-placeholder location="classpath:db.properties" />
        
            <!-- 注册数据源 -->
            <bean id="dataSource" class="${jdbc.dataSourceClass}">
                <property name="driverClass" value="${jdbc.driverClassName}" />
                <property name="jdbcUrl" value="${jdbc.url}" />
                <property name="user" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </bean>
        
            <!-- Spring管理SessionFactory -->
            <bean id="sessionFactory"
                class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
                <!-- 1.数据源 -->
                <property name="dataSource" ref="dataSource" />
        
                <!-- 2.Hibernate属性 -->
                <property name="hibernateProperties">
                    <props>
                        <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                        <prop key="hibernate.show_sql">true</prop>
                        <prop key="hibernate.format_sql">true</prop>
                        <prop key="hibernate.hbm2ddl.auto">update</prop>
                    </props>
                </property>
        
                <!-- 3.Hibernate映射文件 -->
                <property name="mappingResources">
                    <list>
                        <value>com/itdream/ssh/domain/Product.hbm.xml</value>
                    </list>
                </property>
            </bean>
        
            <!-- Spring事务管理 -->
            <!-- 注册对应的事务管理器,注入数据源提供连接,这里是session以管理事务 -->
            <bean id="transactionManager"
                class="org.springframework.orm.hibernate5.HibernateTransactionManager">
                <!-- 注入数据源 -->
                <property name="sessionFactory" ref="sessionFactory" />
            </bean>
        
            <!-- 注册事务增强类,注入参数事务管理器,设置事务策略 -->
            <tx:advice id="txAdvice" transaction-manager="transactionManager">
                <tx:attributes>
                    <tx:method name="save*" />
                    <tx:method name="update*" />
                    <tx:method name="delete*" />
                    <tx:method name="find*" read-only="true" />
                </tx:attributes>
            </tx:advice>
        
            <!-- 配置切面 -->
            <aop:config>
                <!-- 定义切入点 -->
                <aop:pointcut expression="execution(* com.itdream.ssh.dao.ProductService.*(..))" id="txPointcut"/>
                
                <!-- 配置切入点与通知的关联 -->
                <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
            </aop:config>
        
            <!-- Spring容器中bean的装配 -->
            <!-- 注册ProductDAO -->
            <bean id="productDAO" class="com.itdream.ssh.dao.ProductDAO">
                <!-- 注入SessionFactory -->
                <property name="sessionFactory" ref="sessionFactory" />
            </bean>
        
            <!-- 注册ProductService -->
            <bean id="productService" class="com.itdream.ssh.dao.ProductService">
                <!-- 注入ProductDAO -->
                <property name="productDAO" ref="productDAO" />
            </bean>
        </beans>
    
    

    注意:在导HibernateDaoSupport包时注意版本


    2.3 Spring与Struts2框架的整合

    完全整合与半整合两种方式。两种方式方法类似,完全整合在半整合的基础上使用applicationContext.xml中不使用真正的Action的全包名,而是使用伪类名,Struts2拿着这个伪类名去Spring容器里面查找是否注册有该bean,如果有直接从Spring容器中取,否则自己创建。

    这是导入了struts2-spring-plugin-2.3.32.jar包,修改修struts的对象工厂为 spring (StrutsSpringObjectFactory),将默认Struts2创建Action动作类对象的权利优先交给了Spring管理。


    半整合:

    由于有plugin的jar包,对象工厂变为spring之后, autoWire(自动绑定)机制被激活,默认按名称自动注入 bean.在struts.xml中配置jsp页面跳转Action动作类,Action动作类中提供需要注入的ProductService,提供它的setter方法,即完成了半整合.

    完全整合[推荐]:

    因为pluginjar包将对象工厂变为spring,开启了自动绑定机制,它会优先根据struts.xml中配置的class伪类名先去
    Spring工厂中看有没有以这个伪类名注册的bean对象,如果有,从Spring工厂中直接取出来使用,如果没有,Struts2就自己
    new 一个Action对象.
    
    因此,在半整合的基础上,将Struts2页面访问Action的class全包名,改为在applicationContext.xml中注册的bean
    的id名,这样优先查找spring容器时,就能通过Spring创建Action.
    
    ============================================================================
    
    表单页面提交参数:
    <s:form action="product_saveProduct.action" method="post">
        商品名称:<s:textfield name="pname"/><br/>
        商品价格:<s:textfield name="price"/><br/>
        <s:submit value="提交"/>
    </s:form>
    
    struts.xml配置文件配置Action:
        (class内使用伪类名,即applicationContext.xml中Action动作类的注册bean的id)
    <!-- 自定义包,配置Action -->
    <package name="default" namespace="/" extends="struts-default">
        <action name="product_*" class="productAction" method="{1}"></action>
    </package>
    
    
    applicationContext.xml注册Action动作类 :
    
    <!-- 注册ProductAction -->
    <bean id="productAction" class="com.itdream.ssh.web.action.ProductAction" scope="prototype">
        <!-- 注入Service -->
        <property name="productService" ref="productService" />
    </bean>
    
    ============================================================================
    
    按照上面这么配置,Sturts2与Spring就完成了完全整合,Action动作类的创建交由给了Spring管理.并且可以使用Spring的AOP,属性注入等高级功能。
    

    注意:Action是多实例的,而Spring管理的对象是单实例的,因此注册bean的时候,使用scope设置其为多实例prototype


    小结:

    img56.png

    三、解决延迟加载问题

    什么是延迟加载问题 ?

    img57.png
    多表关系时,Spring的查找机制默认是懒加载的,在查找了员工数据,返回到表现层,Session关闭以后,表现层使用list时,
    会发送sql语句查询关联的信息部门,这时候就会出错,因为session已经关闭了。
    

    如何解决延迟加载问题?

    方案一: 配置为立即加载 lazy=false (不推荐 )
        我们查询的数据不一定都需要关联数据,太浪费资源。
    
    方案二: Service方法返回前, 对延迟数据进行初始化  (缺点多写代码 )
    List<Employee> list = dao.findAll (); 
    for(Employee e : list ){
        Hibernate.initialize(e.getDepartment() );
    }
    
    【推荐】方案三: OpenSessionInView 机制 (将Session开启到表现层 最前面 Filter )
    Spring框架提供了一个过滤器OpenSessionInViewFilter,让session对象在WEB层就创建,在WEB层销毁。
    只需要配置该过滤器即可[需要配置在struts2 Filter前面]
    
    web.xml:
    <filter>
    <filter-name>OpenSessionInViewFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>OpenSessionInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    注意:需要在struts2的核心过滤器之前进行配置
    
    OpenSessionInViewFilter原理:  
        在request过程中维持session。延迟session的关闭,直到request结束,再自动关闭session。
    
    缺点:
        如果没有被事务管理的方法, OpenSessionInViewFilter 会将这些方法的事务变为 readOnly 的。
        但是这个问题可以避免,在application的事务管理中:将事务拦截到的方法,都配置事务的属性。都设置好read-only的事务策略。
    

    四、 各配置文件总结

    SSH框架完全整合完毕后,各配置文件的最终形态:(以后使用直接修改)

    此次整合用到的jar包37个。

    4.1 web.xml配置文件

    • Spring的核心监听器,将Spring容器与ServletContext绑定,保证Spring容器只有一个.
      • 前提:导入Springweb的jar包
    • OpenSessionView过滤器,避免Spring与Hibernate整合后的延迟加载问题,将Session对象的关闭延迟到表现出。
    • Struts2的前端控制器,拦截所有请求,进行统一处理(初始化,拦截器...)

    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"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
        id="WebApp_ID" version="2.5">
        <display-name>day42_ssh2</display-name>
    
        <!-- Spring的核心监听器 -->
        <listener>
            <!-- Spring提供的ContextLoaderListener监听器 -->
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <!-- 全局参数 -->
        <context-param>
            <!-- 默认加载的配置文件在web-inf里的applicationContext.xml,因此需要修改 -->
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </context-param>
    
        <!-- Struts2前端控制器 -->
        <filter>
            <filter-name>struts2</filter-name>
            <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <welcome-file-list>
            <welcome-file>index.html</welcome-file>
            <welcome-file>index.htm</welcome-file>
            <welcome-file>index.jsp</welcome-file>
            <welcome-file>default.html</welcome-file>
            <welcome-file>default.htm</welcome-file>
            <welcome-file>default.jsp</welcome-file>
        </welcome-file-list>
    </web-app>
    

    4.2 struts.xml配置文件

    • 开启配置文件自动加载
    • 配置Struts2简单样式
    • 根据页面请求,配置对应的Action
      • 这里的class使用伪类名,在applicationContext.xml中配置对应的Action动作类的bean,完成整合

    struts.xml :
    
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
    <struts>
    
        <!-- 关闭开发者模式 -->
        <!-- <constant name="struts.devMode" value="true" /> -->
        <constant name="struts.configuration.xml.reload" value="true" />
    
        <!-- 使用简单样式 -->
        <constant name="struts.ui.theme" value="simple" />
    
        <!-- 自定义包,配置Action -->
        <package name="default" namespace="/" extends="struts-default">
            <action name="product_*" class="productAction" method="{1}"></action>
        </package>
    </struts>
    

    4.3 applicationContext.xml配置文件

    • 配置数据源
    • 这里是与Hibernate整合,因此配置SessionFactory,将hibernate.cfg.xml的所有参数配置都配置到applicationContext.xml配置文件的sessionFactory
      • 注入数据源
      • 配置Hibernate属性
      • 加载Hibernate的映射文件
    • 事务管理的配置
      • 确定增强类Service(注册)
      • 注册Spring提供的事务增强类<tx:advice>相当于注册
        • 注入事务管理器,属性transaction-manager="transactionManager"
        • 配置事务的属性策略read-only等
      • 注册事务管理器
        • <bean id="transactionManager" class="HibernateTransactionManager....">
        • 注入数据源提供连接Session管理事务
      • 配置切面aspect:<aop:config>
        • 定义切入点<aop:pointcut>
        • 配置切入点与通知的关联<aop:advisor>
    • Spring容器bean的装配注册
      • 其中注册DAO层,需要注入数据源,使HibernateDaoSupport能够生成HibernateTemplate.

    appliactionContext.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"
        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.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!-- 引入外部配置文件,下面使用${key}取值 -->
        <context:property-placeholder location="classpath:db.properties" />
    
        <!-- 注册数据源 -->
        <bean id="dataSource" class="${jdbc.dataSourceClass}">
            <property name="driverClass" value="${jdbc.driverClassName}" />
            <property name="jdbcUrl" value="${jdbc.url}" />
            <property name="user" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
        </bean>
    
        <!-- Spring管理SessionFactory -->
        <bean id="sessionFactory"
            class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
            <!-- 1.数据源 -->
            <property name="dataSource" ref="dataSource" />
    
            <!-- 2.Hibernate属性 -->
            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                    <prop key="hibernate.show_sql">true</prop>
                    <prop key="hibernate.format_sql">true</prop>
                    <prop key="hibernate.hbm2ddl.auto">update</prop>
                </props>
            </property>
    
            <!-- 3.Hibernate映射文件 -->
            <property name="mappingResources">
                <list>
                    <value>com/itdream/ssh/domain/Product.hbm.xml</value>
                </list>
            </property>
        </bean>
    
        <!-- Spring事务管理 -->
        <!-- 注册对应的事务管理器,注入数据源提供连接,这里是session以管理事务 -->
        <bean id="transactionManager"
            class="org.springframework.orm.hibernate5.HibernateTransactionManager">
            <!-- 注入数据源 -->
            <property name="sessionFactory" ref="sessionFactory" />
        </bean>
    
        <!-- 注册事务增强类,注入参数事务管理器,设置事务策略 -->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="save*" />
                <tx:method name="update*" />
                <tx:method name="delete*" />
                <tx:method name="find*" read-only="true" />
            </tx:attributes>
        </tx:advice>
    
        <!-- 配置切面 -->
        <aop:config>
            <!-- 定义切入点 -->
            <aop:pointcut
                expression="execution(* com.itdream.ssh.service.ProductService.*(..))"
                id="txPointcut" />
    
            <!-- 配置切入点与通知的关联 -->
            <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
        </aop:config>
    
        <!-- Spring容器中bean的装配 -->
        <!-- 注册ProductDAO -->
        <bean id="productDAO" class="com.itdream.ssh.dao.ProductDAO">
            <!-- 注入SessionFactory -->
            <property name="sessionFactory" ref="sessionFactory" />
        </bean>
    
        <!-- 注册ProductService -->
        <bean id="productService" class="com.itdream.ssh.service.ProductService">
            <!-- 注入ProductDAO -->
            <property name="productDAO" ref="productDAO" />
        </bean>
    
        <!-- 注册ProductAction -->
        <bean id="productAction" class="com.itdream.ssh.web.action.ProductAction" scope="prototype">
            <!-- 注入Service -->
            <property name="productService" ref="productService" />
        </bean>
    </beans>
    

    4.4 log4j.properties与自定义的db.properties

    log4j.properties:
    ### direct log messages to stdout ###
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target=System.err
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
    
    ### direct messages to file mylog.log ###
    log4j.appender.file=org.apache.log4j.FileAppender
    log4j.appender.file.File=d:\\mylog.log
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
    
    ### set log levels - for more verbose logging change 'info' to 'debug' ###
    log4j.rootLogger=info, stdout,file
    
    ----------------------------------------------------------------------------
    
    db.properties:
        jdbc.dataSourceClass=com.mchange.v2.c3p0.ComboPooledDataSource
        jdbc.driverClassName=com.mysql.jdbc.Driver
        jdbc.url=jdbc:mysql://localhost:3306/ssh
        jdbc.username=root
        jdbc.password=root
    

    4.5 持久化类对应的映射文件Xxx.hbm.xml

    这里面主要为了展示一下,命名查询的hql语句的定义:

    <!-- 全局hql语句 -->
    <query name="Product.findByNameLike">
        from Product where pname like ?
    </query>
    

    总结完毕。

    相关文章

      网友评论

        本文标题:04_Spring-SSH框架整合

        本文链接:https://www.haomeiwen.com/subject/abkkkxtx.html