Struts2+spring+hibernate整合

第四章 搭建SSH框架

本章目标

  • 掌握Spring与Struts 2的集成重点(难点)
  • 掌握Spring与Hibernate的集成重点(难点)

SSH系统程序架构

SSH架构

  • Struts 2 + Spring + Hibernate
  • 以Spring作为核心框架,数据持久化使用Hibernate完成,表现层使用Struts 2
  • Spring提供对象管理、面向切面编程等实用功能
  • 通过Spring提供的服务简化编码、降低开发难度、提高开发效率

使用SSH架构开发登录功能

用户登录

  • 登录成功,保存当前用户到Session,根据角色跳转
  • 登录失败,转发回登录页面,并提示错误信息

用户注册

  • 注册成功,跳转到登录页面
  • 注册失败,返回注册页面,并提示错误信息。

开发准备:添加所需的jar文件

SSH整合体验最不好的就是添加jar包,由于三个框架所依赖的jar包非常多,其中有一些jar包可能冲突,我们应该将冲突的jar包,保留高级版本的,删掉低级版本的。

Spring与Struts 2集成

实现步骤

  • 添加struts2-spring-plugin-xxx.jar
  • 按照名称匹配的原则定义业务Bean和Action中的setter方法
  • 在struts.xml正常配置Action

分析

  • Action实例如何创建?
  • Spring创建的业务Bean如何注入给Action?

配置web.xml文件



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


    struts2
    /*



    contextConfigLocation
    
    classpath:spring.xml,classpath:springDao.xml


    
    org.springframework.web.context.ContextLoaderListener

Spring整合Struts2自动装配

  • Spring和Struts2整合的关键是如何让Spring来管理Struts2的Action。
  • Spring的自动装配:
    • 导入struts2-spring-plugin-2.3.24.jar包后,Struts2会将Action对象的管理交由Spring来管理。
    • Spring默认按照byname的方式进行自动装配,会自动查找Spring容器中是否有同名的bean。如果没有找到,就不执行注入。
  • 如何使用自动装配:设置元素的autowire属性
    • autowire:自动装配类型(byName,byType),默认为byName。
    • autowire-candidate:设值是否支持自动注入,(true,false),默认为true

Struts 2和Spring集成的第二种方式

spring.xml配置



    

struts.xml配置


    
    
        success.jsp
        login.jsp
    

提示:

  1. 采用此种配置方式时,Action的实例由Spring创建,Struts 2插件的工厂类只需根据Action Bean的id查找该组件使用即可
  2. 此种方式可以为Action进行更灵活的配置,但代价是在Spring配置文件中需要定义很多Action Bean,增加了配置工作量,如非必需并非首选
  3. 采用此种配置方式,同样需要添加struts2-spring-plugin-xxx.jar文件

添加编码格式过滤器

Spring为了避免Struts2中的乱码问题,给我们提供了一个默认的编码过滤器。



    字符集过滤器
    encodingFilter
    org.springframework.web.filter.CharacterEncodingFilter
    
        字符集编码
        encoding
        UTF-8
    


    encodingFilter
    /*

小结

  • Spring和Struts2进行整合。
  • Spring开启Struts2编码过滤器。

Spring整合Hibernate的优势

  • 通用的资源管理,直接管理Hibernate底层的DataSource,SessionFactory。
  • 有效的Session管理。
  • 声明式的事务管理。
  • 异常包装。
  • 工具类封装。

Spring管理Hibernate配置文件

  • 在Spring中Hibernate的配置基本可以交由Spring来进行管理。
  • 由于Spring的Dao层文件较为独立,所以推荐单独创建一个springdao.xml文件用来存放数据层的配置信息。

SpringDao.xml文件

SpringDao中用到许多spring的特性,比如aop,tx,context等。所以需要导入schema头文件。




c3p0连接池配置

  • 一般项目中使用连接池进行数据库连接,这里我们选用c3p0连接池。首先添加c3p0的连接池信息。
  • 首先需要导入c3p0连接池对应的驱动包。
  • 当然也可以选用其他连接池信息,只需要修改对应的驱动类和参数即可。
  • 连接池信息有两种配置方案:
    • 在springDao文件中配置。
    • 在hibernate.cfg.xml文件配置。

Springdao.xml配置方案

  • 在springDao文件中配置。


    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

Hibernate连接池配置方案

  • 在hibernate.cfg.xml文件配置

    
    org.gjt.mm.mysql.Driver
    root
    jdbc:mysql://localhost:3306/test
    root
    org.hibernate.dialect.MySQL5Dialect
    
    
    20
    
    5
    
    120
    
    100
    
    120
    
    2
    
    true

sessionFactory工厂配置

  • Hibernate中的sessionFactory工厂,在Spring中可以交由Spring来进行维护和管理。


    
    
    
    
    
    
        
            
            classpath:com/lxit/ssh/entities/mapper/*.hbm.xml
        
    

  • hibernate.cfg.xml

    
        
        org.hibernate.dialect.MySQL5InnoDBDialect
        
        true
        
        true
         
        
        
        update
    

丢弃hibernate.cfg.xml配置文件的sessionFactory配置



    
    
    
    
        
            
            classpath:com/znsd/ssh/bean/*.hbm.xml
        
    
    
    
        
            
            org.hibernate.dialect.MySQL5InnoDBDialect
            true
            true
            update
            org.springframework.orm.hibernate4.SpringSessionContext
        
    
    
    

dataSource配置文件的提取

  • 添加jdbc.properties配置文件
  ## jdbc 连接配置
  jdbc.driver=com.mysql.jdbc.Driver
  jdbc.url=jdbc:mysql://192.168.41.10:3306/test
  jdbc.user=znsd_test
  jdbc.password=123456
  ## c3p0 数据源配置
  c3p0.minPoolSize=15
  c3p0.maxPoolSize=25
  c3p0.acquireIncrement=15
  c3p0.checkoutTimeout=10000
  c3p0.initialPoolSize=20
  c3p0.maxIdleTime=20
  c3p0.idleConnectionTestPeriod=60000
  • spring加载配置文件






    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

配置事务

  • 在Hibernate中,如果实现增加、修改、删除必须使用事务处理。


    



    
    
        
        
        

        
        
        
        

        
        

        
        

        
    

属性介绍

  • 是Spring中事务通知类标签,这里用来定义Hibernate中的事务。
  • 常用属性如下。
属性 默认值 描述
name(必选)   必选,与事务关联的方法名,通配符()可以用来指定一批关联到相同的事务属性的方法,如"add"、"get*"、"select*"等。
propagation REQUIRED 事务传播行为
isolation DEFAULT 事务隔离级别
timeout -1 超时事件,单位为秒
read-only false 是否只读

事务传播行为

  • Spring事务传播行为有以下类型:
事务传播行为类型 说明
PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是 最常见的选择。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 PROPAGATION_REQUIRED 类似的操作。

事务隔离级别

数据库并发操作存在的异常情况:

  • 更新丢失
  • 脏读取
  • 不可重复读取
  • 两次更新问题
  • 幻读

数据库隔离级别:

  • 未授权读
  • 授权读取
  • 可重复读
  • 串行

 Spring可以简化Hibernate编码

  • 使用HibernateTemplate来简化Hibernate编程
public void addEmployee(Employee employee) {
    Transaction tx = null;
    try {
        tx = HibernateUtil.getSession().beginTransaction();
        HibernateUtil.getSession().save(employee);
        tx.commit();
    } catch(RuntimeException re) {
        tx.rollback();
        throw re;
    } finally {
        HibernateUtil.closeSession();
    }
}

上面的流程化的代码仍显烦琐,可以改为一下代码,Spring的目标是使现有的Java EE技术更易用

public void addEmployee(Employee employee) {
    this.getHibernateTemplate().save(employee);
}

HibernateTemplate类

  • HibernateTemplate类似于前面我们定义的HibernateUtil工具类,只不过这个HibernateTemplate是基于Spring管理的,其实本身就是session的一个代理。功能更加强大。
  • 常用方法:

    • get/load存取单条数据:
    (Teacher)this.hibernateTemplate.get(Teacher.class, id);  
    
    • find/iterate查询操作:
    (List)this.hibernateTemplate().find("from Teacher t where t.age>?", new Integer(age));  
    
    • save/update/saveOrUpdate/delete 保存/更新/删除操作
    this.hibernateTemplate.save(teacher); 
    

使用HibernateDaoSupport基类

实现步骤

  • DAO类继承HibernateDaoSupport
  • 使用getHibernateTemplate()方法获取HibernateTemplate实例完成持久化操作

问题

  • 如何将SessionFactory注入DAO ?
  • 如何创建HibernateTemplate实例?

分析

  • HibernateDaoSupport基类的setSessionFactory()方法

实现数据层的方法

  • 使用Spring+Hibernate实现数据层的用户登录、用户注册、用户查询的方法。
  • public int login(User user);
  • public String addUser(User user);
  • public List getList();

OpenSessionView模式

  • Spring为我们解决Hibernate的Session的关闭与开启问题。
  • Hibernate 允许对关联对象、属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Session 范围之内进行。如果 Service 层返回一个启用了延迟加载功能的领域对象给 Web 层,当 Web 层访问到那些需要延迟加载的数据时,由于加载领域对象的 Hibernate Session 已经关闭,这些导致延迟加载数据的访问异常


    OpenSessionInViewFilter
    org.springframework.orm.hibernate4.support.OpenSessionInViewFilter


    OpenSessionInViewFilter
    *

其他配置

  • 防止内存泄漏
  
  
    org.springframework.web.util.IntrospectorCleanupListener
  
  • 设置Session过期时间
  
  
      15
  

Write operations are not allowed in read-only mode问题解决

错误原因:  这是因为Spring默认将一个名为"readOnly"的属性设置成为true,导致只能对数据库进行“读”操作,不允许进行“写”操作。

解决: 可以使用hibernateTemplate来解决次问题,配置一个HibernateTemplate将检查读的操作属性(checkWriteOperations)设置为false


    
    


    

小结

  • 使用Spring整合Hibernate。
    • 数据库连接池
    • sessionFactory
    • HibernateTemplate
  • Spring中的事务管理
  • OpenSessionView模式
  • 防止内存泄漏
  • 设置session有效事件

分页处理

  • 虽然HibernateTemplate帮我们集成了非常强大的功能,但是灵活性确降低了,比如要实现分页,因为没有提供setFirstResult()方法,所以无法进行分页,那么我们怎么做呢?
  • Hibernate还支持一种回调机制。
  • execute(hibernateCallback);

模板与回调机制

  • 通过HibernateCallback实现分页功能
public List find(final int page, final int size) {
    List result = getHibernateTemplate().execute(
        new HibernateCallback() {
            public Object doInHibernate(Session session)
                        throws HibernateException, SQLException {
                Query query = session.createQuery("from Employee");
                query.setFirstResult((page - 1) * size);
                query.setMaxResults(size);
                return query.list();
            }
        }
    );
    return result;
}

抽取BaseDao

  • 抽取常用功能接口BaseDao。
  public interface BaseDao {

    public void add(T t);

    public void delete(Serializable id);

    public void uodate(T t);

    public T load(Serializable id);

    public T get(Serializable id);

    public List list();

    public List list(String hql, Object[] args);
  }
  • 提供实现类BaseDaoImpl实现BaseDao接口。
  public class BaseDaoImpl extends HibernateDaoSupport implements BaseDao {

    /**
     * 实体类类型(由构造方法自动赋值)
     */
    private Class entityClass = null;

    /**
     * 构造方法,根据实例类自动获取实体类类型
     */
    public BaseDaoImpl() {
        entityClass = this.getSuperClassType(getClass());
    }

    /**
     * 通过反射获取T的类型信息实例
     */
    protected Class getSuperClassType(Class c) {
        Type type = c.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Type[] params = ((ParameterizedType) type).getActualTypeArguments();
            if (!(params[0] instanceof Class)) {
                return Object.class;
            }
            return (Class) params[0];
        }
        return null;
    }

    @Override
    public void add(T t) {
        this.getHibernateTemplate().save(t);
    }

    @Override
    public void delete(Serializable id) {
        this.getHibernateTemplate().delete(this.load(id));
    }

    @Override
    public void uodate(T t) {
        this.getHibernateTemplate().update(t);
    }

    @Override
    public T load(Serializable id) {
        return (T) this.getHibernateTemplate().load(entityClass, id);
    }

    @Override
    public List list() {
        return createCriteria().list();
    }

    @Override
    public List list(String hql, Object[] args) {
        return (List) this.getHibernateTemplate().find(hql, args);
    }

    @Override
    public T get(Serializable id) {
        return (T) this.getHibernateTemplate().get(entityClass, id);
    }

    /**
     * 创建与会话绑定的检索标准对象
     */
    public Criteria createCriteria(Criterion... criterions) {
        return this.createDetachedCriteria(criterions).getExecutableCriteria(this.currentSession());
    }

    /**
     * 创建与会话无关的检索标准对象
     */
    public DetachedCriteria createDetachedCriteria(Criterion... criterions) {
        DetachedCriteria dc = DetachedCriteria.forClass(this.entityClass);
        for (Criterion c : criterions) {
            dc.add(c);
        }
        return dc;
    }
  }

小结

  • 使用Spring集成Hibernate的步骤是什么?
  • 实现Spring和Hibernate集成中的分页。
  • 抽取BaseDao类

总结

  • 实现Spring和Struts 2集成
  • SSH框架整合的系统架构,Action、Service、Dao、SessionFactory
  • 通过HibernateTemplate简化Hibernate DAO的编码
  • 在Dao中使用HibernateCallback接口

你可能感兴趣的:(G高级)