1. 将Strut2,Hibernate,Spring的jar包导入项目(分别建了一个useLibrary),mySql的jar。
2. 先把Struts2跑通
1) 在文本 web.xml中加入struts2的过滤器。
2) 编写struts的配置文件:新建一个叫config的source目录,在该目录下新建一个struts.xml的文件。在config下建一个struts文件夹,在里面创建两个模块自己的struts.xml。在Struts.xml文件中写一个总的package,然后引入两个模块自己的struts.xml.
3) 在webRoot下分别建三个目录装jsp,studentManage(学生管理模块的页面),teacherManage(老师管理模块的页面),common(公共页面)
4) 编写student实体类
5) 编写studentAction,有一个跳转到添加学生页面的方法(gotoAddStudent),有一个保存学生信息的方法(addStudent)。
6) 跑通struts,请求项目,到默认页面,带添加学生跳转到添加学生的页面,点保存跳转到保存成功的页面。
3. 慢慢加入Hibernate
1) 在config source目录下创建一个hibernate.cfg.xml文件。
2) 用Annotation(注解)来配置实体类。
3) 在com.zhengjie.util包里创建一个hibernate的工具类,用于拿sessionFactory,应为这部分代码很固定。
4) 创建studentService和studentServiceImpl,讲述不用spring时,Action引用service时是自己new的。
***********到这里就是struts+Hibernate了,项目:S2SH
4.将Struts2交给spring管理(spring和Struts2的整合)
1)先看下不在web项目中的Spring的使用,项目:Spring_test。Spring是干嘛的,DI,AOP。
2)spring好像还需要commonslogging的jar包,所以先引入commons logging的jar包
3)要想把Struts2交给Spring管理必须在引入一个包是struts的struts_spring_plugin.jar,这事struts2和spring结合用到的一个jar包。
4)为什么要把Action交给Spring管理?交给spring后,Action就不是Struts2自己new了,而是spring去new,struts直接spring容器中去拿。
5)修改struts.xml,告诉struts不要自己newAction了,而是去spring容器中去拿。并且Action的配置时的class属性不用写包+类的具体地址了,而是写在Spring中配置的Action的名字。
<!-- 开发模式 -->
<constant name="struts.devMode" value="true"/>
<!-- 将Action交给Spring管理 -->
<constant name="struts.objectFactory" value="spring"/>
<!-- 自动装配属性时以name为标准 -->
<constant name="struts.objectFactory.spring.autoWire"value="name" />
7) 在config的Source目录下,新建个Spring文件夹,创建applicationContext.xml的spring配置文件。这个不用非的在ClassPath下,因为这些Spring的配置文件位置是要配在web.xml中的,不是自动去ClassPath下找。
8) 在web.xml中配置spring的配置文件位置,spring的监听器,struts2的过滤器。
9) Action中调用Service时就不用自己new了,Spring自己注入了。
10) Struts2交给Spring管理很简单,就是Action不是Struts自己new,而是Spring去new,Struts跟Spring去要。Hibernate交给Spring就稍微复杂一点。
11) 注意:Action是有谁产生的?
a) Action即可以有Struts(Struts和Spring的插件)产生,也可以由Spring产生。
b) 当Struts的配置文件的class属性写的是Spring中配置的Action的对象的名字时,Action就是Spring产生的,Spring必须配置Action对象。
<action name="studentAction"class="studentAction">
<result name="success">/studentManage/AddStudent.jsp</result>
</action>
c) 当Struts的配置文件的class属性写的是Action的类路径,Action就是Struts自己产生的,并且里面的属性是Struts去Spring容器中找相应的对象来注入。按什么类型(name或type)注入struts有配置,<constant name="struts.objectFactory.spring.autoWire"value="name" />。这时Action是struts自己产生的,所以在Spring中配不配置Action对象是没有关系的。
d) Spring不会管理Scope为prototype的bean的生命周期的。Spring只管每次要这个bean时new出来,但不管他什么时候销毁。按理说Struts的Action对象在用完之后应该马上销毁。所以这个销毁可能是struts2和spring插件(struts提供的)控制的,或者Action不要让spring产生了,直接让struts自己产生。
4. 把hibernate交给spring管理
1.DataSource,是JDK的一个接口。DataSource接口中有一个方法是getConnection(),所以DataSource是java提供的一个标准,一个获取连接的标准,所以的其他的DataSource一般都实现了DataSource接口,这样DateSource的接口API就被java统一了。
2.Spring经常用的数据库连接池是DBCP。要把DBCP的jar包引入。然后再Spring的配置文件中配上DBCP的一个bean。
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/ssh"/>
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
注意:DBCP连接池用到commons_pool.jar
3.上面配置数据源的属性值时,也可以把属性值配置在property文件中,如下:
(1)先把property文件加载进Spring
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:config/*.properties</value>
</list>
</property>
</bean>
(2)加载了property文件的bean后,数据源就可以按下面配置了。
<bean id="dataSourceSpied" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
<property name="driverClassName"value="${jdbc.driverClassName}" />
<property name="url"value="${jdbc.url}" />
<property name="username"value="${jdbc.username}" />
<property name="password"value="${jdbc.password}" />
<property name="maxActive"value="${jdbc.maxActive}" />
</bean>
4.下一步用这个DataSource时,一般是在Dao层的实现类中加一个DateSource的属性,然后把DBCP的Bean注入进去。然后再DAO中直接用这个dataSource来拿连接使用。有时会写一个总的DAO层的类,只往这个总的Dao层的类中注入DBCP,然后所有的DAO都继承这个总的DAO。有的系统分层式没有DAO层,那就把dateSource直接注入到service层的实现类。
5.Spring和hibernate整合第一步是将hibernate的sessionFactory交给Spring管理,就是将hibernate的SessionFactory配置成spring的一个bean。这个bean用的是spring写的sessionFactory不是hibernate自己的,但是Spring这个sessionFactory实现了hibernate的sessionFactory接口(好像并没有实现hibernate的sessionFactory的接口,暂且认为它实现了),spring的sessionFactory也是分为annotation版本的和xml版本的,这个sessionFactory有好多属性药配置,其中就有上面配置的datasource。如下:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<!-- 配置sessionFactory中要用的数据源 -->
<property name="dataSource"ref="dataSourceSpied" />
<!-- 大对象处理器 -->
<property name="lobHandler"ref="lobHandler" />
<!-- 可以同时支持注解和xml的方式产生映射类-->
<property name="packagesToScan">
<list>
<value>ins.**.model</value>
<value>com.**.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
${hibernate.dialect}
</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
<prop key="hibernate.hbm2ddl.auto">none</prop>
</props>
</property>
</bean>
6.配置了sessionFactory后,在DAO层中就不要把dataSource注入了,直接把sessionFactory注入到DAO的实现类中,在DAO中直接使用sessionFactory。在DAO的实现类中定义一个hibernate的sessionFactory接口的属性,和get,set方法来接受注入,这也说明了Spring的sessionFactory实现了hibernate的sessionFactory接口。在DAO的实现类中就可以这么用hibernate了:
Session session =sessionFactory.openSession()
session.beginTransaction();
session.save(t);
session.getTransaction().commit();
session.close();
这样在Spring配置了sessionFactory后,hibernate自己的配置文件(hibernate.cfg.xml)就没什么用了。
7.Spring管理hibernate的事务
(1) 事务的边界,一般设在service的方法上。所以个人认为一个Action的方法就应该对应一个Service的方法,而且这个Action的方法就只调用它对应的service方法。但一个Action可能要做这么几个动作,先校验,再插入,再查询,而且Action要得到校验的结果,也要获得查询的结果,这样要把这三个逻辑放在一个service的方法的话,那这个service的方法的返回值是什么呢?是一个MAP<string,Object>可以,单感觉很别扭。还是把这三个逻辑分别写在三个service方法中,但是这样的话如果几个逻辑中有两个以上的涉及保存或更新的话,就会不在一个事物中。还是只把涉及保存和更新的逻辑放在一个service方法中,但是这样的话涉及保存更新的逻辑可能不是相邻的,也没法把他们放在一个service方法中。到底什么方式最合适待讨论。
(2) 首先要配置一个bean,这个bean是管理hibenate事物的bean,它有一个属性是sessionFactory,把我们配置的sessionFactory注入给它,因为他需要sessionFactory的配置信息,其实这个管理类就是AOP的一个切面类。
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
其实配置了事物管理以后,session就是有这个事务管理类产生的了,而在用session时必须用sessionFactory的getCurrentSession(),他会拿事物管理类在方法开始时创建的那个session。
这个事物管理类还有很多属性可配置,比如:事物的传播特性等,默认是如果有事物了就不会再创建一个事务。
(3) 配置事物也分为xml版本和Annotation版本。
(4) Annation版本时要在spring配置文件中加上下面一句<tx:annotation-driventransaction-manager="txManager"/>,然后再需要加事物的service方法上,写上注解@Transactional。
(5) 这个事务的管理类会在方法开始时拿一个session,然后开启事物,在方法后面提交事物,如果中间抛出异常就自动的回滚(默认只有抛出的是RuntimeException时才会回滚,因为hibernate抛出的异常都是RuntimeException,回滚的异常类型是可以配置的)。所以我们不能自己开启开启或提交事物或回滚了。
(6) 用XML配置时,首先还是把切面类配置为一个bean。事务的AOP配置有点特殊,
a) 首先要配置一个事物的建议,就是说对这个事物的一些建议,主要配置了哪些方法时事物用read_only的哪些方法用read_write,而且要配置事物管理类时那哪个。这样提高效率。如下配置:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="is*" read-only="true"
propagation="SUPPORTS"/>
<tx:method name="login*" read-only="true"
propagation="SUPPORTS"/>
<tx:method name="get*" read-only="true"
propagation="SUPPORTS"/>
<tx:method name="find*" read-only="true"
propagation="SUPPORTS"/>
<tx:method name="list*" read-only="true"
propagation="SUPPORTS"/>
<tx:method name="query*" read-only="true"
propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
read-only:事务是否只读
propagation:事务的传播特性
b) 然后再配置一个AOP标签,在里面配置一些建议者标签<aop:advisor>,其实建议者标签就是包含了一个pointCut(切入点集合),和一个建议<tx:advice>。在AOP标签里只配置<aop:advisor>就够了,你不用配置切面类(<aop:aspect>)和切入点集合(<aop:pointcut>)。因为<aop:advisor>中有了pointcut,而且有了建议者,而建议者中又有我们的切面类(事务管理类)。如下配置:
<aop:config proxy-target-class="true">
<aop:advisor pointcut="execution(public* ins..*ServiceSpringImpl.*(..))" advice-ref="txAdvice"/>
<aop:advisor pointcut="execution(public* *..*service..*Service*Impl.*(..))" advice-ref="txAdvice"/>
</aop:config>
(7) 配好事务管理后,我们的DAO层,代码就这么写了,只是拿到session,然后用session相应的方法就行了:
Session session = sessionFactory.getCurrentSession();
session.save(t);
注意:这时,拿session必须用sessionFactory的getCurrentSession()方法,而且自己不用打开事务提价事务或回滚事务。
8.hibernate交给spring管理总结:先在Spring中配置一个dataSource,再配置一个sessionFactory并把datasource注给sessionFactory,再配置一个hibernate的事物管理类,在配置一个事物管理类的建议(<tx:advice>), 再配置一个AOP标签把书屋管理建议用<aop:advisor>配进去。Spring还依赖aopalliance.jar,aspectjweaver.jar,cglib-nodep-2.1_3。jar,asm-2.2.3。jar。
5.Spring对hibernate的封装
1.spring对hibernate的使用进行了一些封装。
2.spring对hibernate的封装有几种方式:
(1) 方式一:spring对hibernate的封装主要运用一种设计模式叫template method(模板方法)。
a) 首先要在spring中配置一个hibernateTemplate的bean。并把sessionFactory注入给它。
<bean id="hibernateTemplate"
class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory"ref="sessionFactory" />
</bean>
b) 用的时候就把hibernateTemplate注入到DAO实现类中,然后直接使用。
hibernateTemplate.save(s);我们不用管那session,提交session等。hibernateTemplate提供了save(),Load()等一些方法,这些方法都已经为我们封装好了。
(2) 方式二:HibernateDaoSupport方式。HibernateDaoSupport是spring提供的一个抽象类,我们的Dao实现类从它继承来用它提供的一些方法,但这个HibernateDaoSupport需要注入一个sessionFactory或一个hibernateTemplate,所以在配置我们的Dao实现类时就要注入一个sessionFactory或hibernateTemplate,起始是注入给它的父类的。所以这种方式不能用Annotation注解我们的Dao实现类,因为我们的Dao实现类中没有sessionFactory或hibernateTemplate属性和set方法,所以只能用XML方式来配置我们的DAO实现类。
a)Dao的实现类要继承HibernateDaoSupport
publicclass StudentServiceImpl extends HibernateDaoSupport implementsStudentService
b)要往Dao的实现类中注入hibernateTemplate或sessionFactory
<bean id="studentService" class="com.s2sh.service.StudentServiceImpl">
<property name="hibernateTemplate" ref="hibernateTemplate"/>
</bean>
c) 然后直接用HibernateDaoSupport里面的方法就行了。可以拿到hibernateTemplate使用:this.getHibernateTemplate().save(t);
(3) 方式二有一个缺点就是,所有的Dao实现类都去实现HibernateDaoSupport的话,那你每一个Dao的实现类都得注入一遍hibernateFactory或sessionFactory,麻烦。所以我们可以再抽象出一个我们所有Dao层实现类的一个总的Dao实现类,可以叫做AbstrctDao,然后让AbstractDao自己继承HibernateDaoSupport并注入sessionFactory或hibernateTemplate,并且让我们所有的DAO层实现类继承AbstrctDao,这样我们所有的DAO层实现类及可以用HibernateDaoSupport提供的方法有不用每个都注入了。