之前写过一篇类似的文章,现在回过头来看很糟糕。 很多人在第一次大框架的时候感到很迷茫,包括本人。尤其是jar包的问题,那么多,到底哪些该加,哪些不该加。网上虽然有很多教程和文章,但都是把一堆jar包垒上,然后给出一个demo。诺,照这样做,框架就搭好了。看,我还加了cglib,aspectj呢。
其实,新手应该从搭一个SSH的最小系统开始,以后熟练了,再玩点高大上的,用aspectj,cglib之类的。
什么是最小系统?
计算机或计算机相关专业都学过单片机,单片机有个最小系统,它由三个部分组成:单片机+晶振电路+复位电路。它用最少的元件组成了可以工作的单片机系统。 此处省略一些字。
那么我们的SSH最小系统是什么呢?
在我心目中,SSH的最小系统应该是这样:
很简单,就是MVC分层,实现基本的增删改查操作。 难点就在于事务的理解和配置。涉及到更新操作(增,删,改)是要开启事务的,请知悉。没有jdbc编程基础,知道这点就足够了。
准备工作:从官网下载这些:
spring-framework-4.0.2.RELEASE-dist.zip,
hibernate-release-4.3.5.Final.zip,
struts-2.3.16.1-all.zip,
aopalliance.zip
(spring-aop.jar依赖这个jar包,spring没有给出这个jar包很可恶,官方文档也不提),
aspectj-1.8.0.M1.jar(
将此jar包解压,拿出aspectjweaver.jar。spring自己的AOP 虽然没有使用AspectJ功能,但是复用了这个jar的某些类,没有给出这个jar包很可恶,官方文档也不提。这个链接很重要,一定要看看,http://stackoverflow.com/questions/11446893/spring-aop-why-do-i-need-aspectjweaver)
C:\Program Files\MySQL\MySQL Connector J\mysql-connector-java-5.1.34-bin.jar (装mysql的时候注意勾选上MySQL Connector J,这样才能拿到mysql驱动jar包。以前可以直接下载到,现在不行了)
准备完毕,我们开始:
①新建一个Dynamic Web Project。注意,如果你选择的web module version是3.0,请在向导最后一步勾选上Generate web.xm deployment descriptor。这样才会自动生成一个web.xml。
②拷贝这些jar包到WEB-INF/lib下。
具体过程是这样的:
struts2的jar包:
解压struts-2.3.16.1-all\struts-2.3.16.1\apps\struts2-blank.war. 这是struts2的最小系统。这里有struts2需要的最少jar包。log4j也配置好了,spring官方文档提到spring唯一依赖的一个外部jar包是Log4j.jar。(其实不对还有aopalliance.jar和aspectjweaver.jar) 直接使用这个“空工程”能省我们很多事。 搭SSH我更倾向于从 Struts开始,因为它的jar包最简单。
Hibernate的jar包:
hibernate的jar包还好理解。就是required和optional\c3p0文件夹下的jar包全部拷贝,很贴心不是。有一点需要注意,hibernate里和struts2里有一个重复的jar包——javassist-3.18.1-GA.jar。选择hibernate里的就可以了。 c3p0是Hibernate推荐的数据库连接池,spring推荐的连接池是dbcp,却没有给出jar包。 拷贝c3p0的jar包同时,也请把驱动jar包mysql-connector-java-5.1.34-bin.jar一并拷贝,免得忘了。
spring的jar包:
关键就在这里。不知道该怎么下手,管他3721,Ctrl+A?这样不好,没有用到的功能没必要加冗余jar包。其实理解了spring的结构也很简单,看:
这是spring的结构。
①是spring容器的核心,这4个jar包都要。
②我们是web工程,这个jar包必不可少。
③我们要连数据库,进行增删改查操作。所以jdbc,orm这两个Jar包需要。jdbc需要数据库连接池,所以我们用了一个连接池c3p0。 orm是关系映射对象,是Hibernate干的事,但是spring既然是容器,所以它必须提供这个接口。
④.注意这一块的理解: 增删改需要开启事务。spring提供声明式事务(declarative transaction)。可以是xml-based,也可以是annotation-based。 开启事务是要在方法执行前就要开始的。就是说我们要拦截方法后开启事务,所以需要AOP的支持。AOP和Aspect是分不开的。所以这两个Jar包也是需要的。由于spring-aop.jar依赖aoplliance.jar,而且spring自带
的AOP用了aspectjweaver.jar里的某些类,所以这两个个jar也是需要的(spring给的jar包漏了这两个jar包,实在是不应该)。 强烈建议spring把我提到的这些jar包放在一个required包下,跟Hibernate一样,这样多好。我说的这些已经是最基础的功能了,用的也是最少的jar包,没有半点冗余 。
再强调最后一个jar包。是struts里的一个jar包叫struts2-spring-plugin-2.3.16.1.jar。 因为我们把struts交给spring这个容器管理了,所以需要这个东东。
至此,所有Jar包都解释清楚了。读者不应该再对SSH需要哪些jar包感到疑惑。
struts的配置文件:在解压完struts2-blank这个工程的时候已经有了。 spring说需要唯一一个外部的jar包 log4j.jar 。在这个工程里也有了。
下面开始配置spring和hibernate。 spring和hibernate都配置在一个叫ApplicationContext.xml里。
从哪开始呢。 打开spring官方文档:spring-framework-4.0.2.RELEASE-dist\spring-framework-4.0.2.RELEASE\docs\spring-framework-reference\htmlsingle\index.html
1)Ctrl+F 搜索 ApplicationContext.xml ,我们来到这里
Common configuration
在web.xml里加这个:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/conf/beans/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
这样我们的web工程就使用上了spring。
2)我们知道ApplicationContext.xml其实就是一个bean的集合。 这个配置文件里配置都是各种bean。所以我们搜索beans
来到这里:
The following example shows the basic structure of XML-based configuration metadata:
把这些拷贝到 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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <!-- more bean definitions go here --> </beans>
这样我们就有了一个最简单的spring配置文件了。
3)关键步骤:这样考虑:
连数据库 ->配置dataSouce
使用hibernate的session->配置sessionFactory
请spring帮我们管理事务->配置txManager
( 如果我们使用注解形式开启事务,只需配置 打开注解模式 即可。如果我们使用xml形式配置事务,那么我们还要配置aop。)
我们的dataSouce使用c3p0,直接搜索c3p0.找到这个
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <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> <context:property-placeholder location="jdbc.properties"/>
这就是我们第一步要配的dataSource。连接数据库需要配这些。
然后搜索sessionFactory找到这里:
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
因为我们使用Hibernate4.x所以改成:
<bean id="mySessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
稍作修改:
<context:property-placeholder location="/WEB-INF/conf/db/jdbc.properties"/> <bean id="mySessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="myDataSource" /> <property name="mappingResources"> <list> <value>cn/ahau/ssh/domain/Event.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=${hibernate.dialect} hibernate.show_sql=${hibernate.show_sql} hibernate.hbm2ddl.auto=${hibernate.hbm2ddl.auto} </value> </property> </bean>
注意context标签和property-placeholder属性在context命名空间里。所以要引入context.xsd文件
xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
然后搜索jdbc.properties。 最后这个文件是这样的:
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/test jdbc.username=root jdbc.password=root hibernate.dialect=org.hibernate.dialect.MySQL5Dialect hibernate.show_sql=true hibernate.hbm2ddl.auto=update
下面是最难的事务:(两种方式:xml-based; annotation-based)
搜索 transaction来到这里:
When the above POJO is defined as a bean in a Spring IoC container, the bean instancecan be made transactional by adding merelyone line of XML configuration:
<!-- from the file 'context.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: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/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 <!-- this is the service object that we want to make transactional --> <bean id="fooService" class="x.y.service.DefaultFooService"/> <!-- enable the configuration of transactional behavior based on annotations --> <tx:annotation-driven transaction-manager="txManager"/> <!-- a PlatformTransactionManager is still required --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- (this dependency is defined somewhere else) --> <property name="dataSource" ref="dataSource"/> </bean> <!-- other <bean/> definitions here --> </beans>
i) 注解形式开启事务:其实就一句话, 它是最简单的。我们一般都用这种形式。
<tx:annotation-driven transaction-manager="txManager"/>
然后在service层里的方法上加上这个即可:
@Transactional(rollbackFor = Exception.class, propagation=Propagation.REQUIRED)
注意这回命名空间多了这些:
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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"
知道这一大坨东西怎么来的了吧。就是这样一点一点加上来的。 网上给的都是完整的一大坨,也不知道怎么来的。
ii) xml方式开启事务是这样的:
<!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean below) --> <tx:advice id="txAdvice" transaction-manager="txManager"> <!-- the transactional semantics... --> <tx:attributes> <!-- all methods starting with 'get' are read-only --> <tx:method name="get*" read-only="true"/> <!-- other methods use the default transaction settings (see below) --> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- ensure that the above transactional advice runs for any execution of an operation defined by the FooService interface --> <aop:config> <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/> </aop:config>
最终的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"> <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <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> <context:property-placeholder location="/WEB-INF/conf/db/jdbc.properties"/> <bean id="mySessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="myDataSource" /> <property name="mappingResources"> <list> <value>cn/ahau/ssh/domain/Event.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=${hibernate.dialect} hibernate.show_sql=${hibernate.show_sql} hibernate.hbm2ddl.auto=${hibernate.hbm2ddl.auto} </value> </property> </bean> <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="mySessionFactory" /> </bean> <!-- declarative transaction annotation-based --> <!-- enable the configuration of transactional behavior based on annotations --> <!-- <tx:annotation-driven transaction-manager="txManager"/> --> <!-- declarative transaction XML-based --> <!-- the transactional advice (what happens; see the <aop:advisor/> bean below) --> <tx:advice id="txAdvice" transaction-manager="txManager"> <!-- the transactional semantics... --> <tx:attributes> <!-- all methods starting with get are read-only --> <tx:method name="query*" read-only="true"/> <!-- other methods use the default transaction settings (see below) --> <tx:method name="update*" read-only="false" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!-- ensure that the above transactional advice runs for any execution of an operation defined by the FooService interface --> <aop:config> <aop:pointcut id="serviceOperation" expression="execution(* cn.ahau.ssh.service.impl.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/> </aop:config> <!-- other <bean/> definitions here --> <bean id="baseAction" class="cn.ahau.ssh.common.action.BaseAction" /> <bean id="eventAction" class="cn.ahau.ssh.action.EventAction"> <property name="eventService" ref="eventService"/> </bean> <bean id="eventService" class="cn.ahau.ssh.service.impl.EventServiceImpl"> <property name="eventDao" ref="eventDao"/> </bean> <bean id="eventDao" class="cn.ahau.ssh.dao.impl.EventDaoImpl"> <property name="sessionFactory" ref="mySessionFactory"/> </bean> </beans>
最后解释一下这句话:
<bean id="eventDao" class="cn.ahau.ssh.dao.impl.EventDaoImpl"> <property name="sessionFactory" ref="mySessionFactory"/> </bean>
因为我们的daoimpl里有这个
private HibernateTemplate hibernateTemplate; public void setSessionFactory(SessionFactory sessionFactory) { this.hibernateTemplate = new HibernateTemplate(sessionFactory); }
我们让spring管理hibernate。所有session都让spring帮我们打开和关闭。 spring的HibernateTemplate类需要sessionFactory。所以这里只用一个setter注入sessionFactory即可。这段代码在spring的文档里也有。这文档写的到位。
至此SSH配置完毕。也许还有没说清楚的地方。 源码奉上。 希望大家养成看文档的好习惯,也许一开始我们并不知道从哪下手,没关系,先弄清楚我们要做什么,做这些东西我们需要什么。摸清楚了大致流程,就只管Ctrl+F往文档上招呼。笔者当初在搭这个框架的时候感觉很棘手,搭了很多次,写点心得希望对你有帮助。
最后一个小插曲。 如果用annotation-based方式开启事务 aspectjweaver.jar可以不加。 但是用xml-based方式配置事务,这个jar必须要加。读者可以自己试一下。 在maven工程中aspectjweaver.jar是必须要加的,不然启动报错。
这是下载链接:
http://download.csdn.net/detail/ahau10/8951449