04_Spring-SSH框架整合

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的日志包)
04_Spring-SSH框架整合_第1张图片
img54.png
1.2 Sturts2的配置文件
1. 修改web.xml配置Struts2的前端控制器
    
    
        struts2
        org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    

    
        struts2
        /*
    


2. 配置Sturts2的核心配置文件struts2.xml到src(从模板中复制,删除到最简单的配置)
    如果要添加配置提示,根据DTD文件添加到Xml Catalog中
        
    1. 关闭开发者模式(常量设置从/org/apache/struts2/default.properties中查找)
        缺点:开发者模式不能处理ajax的异常
        但我们需要自动加载配置文件的功能,因此要开启自动加载配置文件的开关

    2. 修改Sturts2的前端样式为simple
    
    
    
    
    
        
        
        
    
        
        
    
        
        
        
    


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的创建起到监听作用。



    
    org.springframework.web.context.ContextLoaderListener



    
    contextConfigLocation
    classpath:applicationContext.xml

2.3 Spring的核心配置文件applicationContext.xml

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

头约束包括:beans,context,tx,aop
-----------------------------------------------------------------------------





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目录下






    
        
        com.mysql.jdbc.Driver
        jdbc:mysql://localhost:3306/hibernate_day02
        root
        root

        
        thread

        
        
        org.hibernate.dialect.MySQL5Dialect

        
        true
        true

        
        update

        
        4

        
        org.hibernate.c3p0.internal.C3P0ConnectionProvider
        
        5
        
        20
        
        120
        
        120
        
        120
        
        2
        
        false

        
        
    


到这里,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:



    
 
    
    
        
        
            
        
        
        
        
        
    
 

-----------------------------------------------------------------------------

在Hibernate.cfg.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


    
    
    
    
    
        
        
        
        
    


2. 将hibernate.cfg.xml的参数完全配置到applicationContext.xml中,由Spring管理SessionFactory.这样Spring容器创建的时候,会创建注入了数据源的SessionFacotory.

**这里注意导入LocalSessionFactoryBean的时候,不要导错版本的全包名,选择Hibernate5**

    
    
        
        
        
        
        
            
                org.hibernate.dialect.MySQL5Dialect
                true
                true
                update
            
        
        
        
        
            
                com/itdream/ssh/domain/Product.hbm.xml
            
        
    

修改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可以直接获取使用。

04_Spring-SSH框架整合_第2张图片
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 findAll() {
        // 方式一:Spring提供了简单的方式
        return getHibernateTemplate().loadAll(Product.class);
        // 方式二:使用hql查询
        // return getHibernateTemplate().find("from Product");
    }

    // ------复杂查询-----------
    // 查询id大于x的商品(HQL语句查询)
    public List findGreaterthanID(Integer pid) {
        return (List) getHibernateTemplate().find("form Product where pid > ?", pid);
    }

    // 命名查询(sql语句与java代码解耦,写在Product.hbm.xml中)
    // 模糊查询
    public List findByNamedQuery(String name) {
        return (List) getHibernateTemplate().findByNamedQuery("Product.findByNameLike", "%" + name + "%");
    }

    // 模糊查询(Criteria离线查询)
    public List findByCriteria(DetachedCriteria criteria) {
        return (List) 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 findAllProduct() {
        return productDAO.findAll();
    }

    public List findProductsGreaterthanID(Integer pid) {
        return productDAO.findGreaterthanID(pid);
    }

    // Criteria离线查询
    public List findProductsByCriteria(DetachedCriteria criteria) {
        return productDAO.findByCriteria(criteria);
    }

    // 命名查询
    public List findByNamedQuery(String name) {
        return productDAO.findByNamedQuery(name);
    }
}


Product.hbm.xml中配置命名查询的语句:


    from Product where pname like ?


-------------------------------------------------------------------------

在applicationContext.xml中注册ProductDAO和ProductService:




    
    




    
    


---------------------------------------------------------------------------

为上面ProductService中的所有方法配置事务管理:(基于AOP的Spring写好的增强类)



    
    




    
        
        
        
        
    




    
    
    
    
    


----------------------------------------------------------------------------

测试:

@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 allProducts = productService.findAllProduct();
        System.out.println(allProducts);
    }

    @Test
    public void findProductsByCriteriaTest() {
        DetachedCriteria criteria = DetachedCriteria.forClass(Product.class);
        criteria.add(Restrictions.like("pname", "%米%"));
        List productListByCriteria = productService.findProductsByCriteria(criteria);
        System.out.println(productListByCriteria);
    }

    // 命名查询测试
    @Test
    public void findProductsByNameQueryTest() {
        List listByNameQuery = productService.findByNamedQuery("%米%");
        System.out.println(listByNameQuery);
    }
}

测试成功

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

  • 导包
  • Hibernate将SessionFactory交由Spring管理
  • Spring对Service层的方法进行事务管理

    applicationContext.xml的完全配置:(以后可以直接复制修改)
    
    
    
    
        
        
    
        
        
            
            
            
            
        
    
        
        
            
            
    
            
            
                
                    org.hibernate.dialect.MySQL5Dialect
                    true
                    true
                    update
                
            
    
            
            
                
                    com/itdream/ssh/domain/Product.hbm.xml
                
            
        
    
        
        
        
            
            
        
    
        
        
            
                
                
                
                
            
        
    
        
        
            
            
            
            
            
        
    
        
        
        
            
            
        
    
        
        
            
            
        
    

注意:在导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.

============================================================================

表单页面提交参数:

    商品名称:
商品价格:
struts.xml配置文件配置Action: (class内使用伪类名,即applicationContext.xml中Action动作类的注册bean的id) applicationContext.xml注册Action动作类 : ============================================================================ 按照上面这么配置,Sturts2与Spring就完成了完全整合,Action动作类的创建交由给了Spring管理.并且可以使用Spring的AOP,属性注入等高级功能。

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


小结:

04_Spring-SSH框架整合_第3张图片
img56.png

三、解决延迟加载问题

什么是延迟加载问题 ?

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

如何解决延迟加载问题?

方案一: 配置为立即加载 lazy=false (不推荐 )
    我们查询的数据不一定都需要关联数据,太浪费资源。

方案二: Service方法返回前, 对延迟数据进行初始化  (缺点多写代码 )
List list = dao.findAll (); 
for(Employee e : list ){
    Hibernate.initialize(e.getDepartment() );
}

【推荐】方案三: OpenSessionInView 机制 (将Session开启到表现层 最前面 Filter )
Spring框架提供了一个过滤器OpenSessionInViewFilter,让session对象在WEB层就创建,在WEB层销毁。
只需要配置该过滤器即可[需要配置在struts2 Filter前面]

web.xml:

OpenSessionInViewFilter
org.springframework.orm.hibernate5.support.OpenSessionInViewFilter


OpenSessionInViewFilter
/*


注意:需要在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 :



    day42_ssh2

    
    
        
        org.springframework.web.context.ContextLoaderListener
    
    
    
        
        contextConfigLocation
        classpath:applicationContext.xml
    

    
    
        struts2
        org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    

    
        struts2
        /*
    

    
        index.html
        index.htm
        index.jsp
        default.html
        default.htm
        default.jsp
    

4.2 struts.xml配置文件

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

struts.xml :





    
    
    

    
    

    
    
        
    

4.3 applicationContext.xml配置文件

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

appliactionContext.xml:




    
    

    
    
        
        
        
        
    

    
    
        
        

        
        
            
                org.hibernate.dialect.MySQL5Dialect
                true
                true
                update
            
        

        
        
            
                com/itdream/ssh/domain/Product.hbm.xml
            
        
    

    
    
    
        
        
    

    
    
        
            
            
            
            
        
    

    
    
        
        

        
        
    

    
    
    
        
        
    

    
    
        
        
    

    
    
        
        
    


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语句的定义:



    from Product where pname like ?


总结完毕。

你可能感兴趣的:(04_Spring-SSH框架整合)