本文转载于http://blog.csdn.net/JackieLiuLixi/article/details/37910743
Spring4.0.2+Hibernate4.5.1+struts2.3.16.1。这三个目前都是官网上最新的且是稳定版的(Stable)。建议大家去官网上下,其中spring的连接有些慢,为了下载它我还特地开了个迅雷会员呢。
虽然这些包都是官网下载的,但是集成SSH还需要些额外jar包。建议大家也都到官网上下载。我的全都是从官网上下载的,而且还是最新的可用版本。我上传到这里了wwwwwwww。大家可以直接下载。
1.新建Dynamic Web Project,注意Dynamic web module version要选2.5。如果你用了默认的3.0。刚建好的工程下WEB-INF/下将没有web.xml。 但是这样会导致新建的工程默认使用Jdk1.5。这会导致你的项目中不能使用@Resource。
解决办法。 右键工程-->build path-->configure build path,选择libraries标签,双击JRE System Library ,选中workspace default jre。我的是jdk1.7。
2.集成spring与Hibernate。这一步集成好了,可以用Junit先测试一下。我们开始:
将如下包拷贝到WEB-INF/lib下,并add to buid path。就这么个看似简单的加jar包都会出问题。我看到有些人只把jar 包加入到WEB-INF/lib下就完了,myeclipse会自动将jar包加入到环境变量中,但咱们免费的eclipse没有那么智能要自己右键 build path-->add to build path才行。 这个倒还好,更重要的是 不 要 右击 项目名,直接 build path-->configure build path。 我之前就是这么干的。这样看起来很好,好像不会占用太多空间,可是这是要付出代价的,直接报错! 这点空间咱省不得。
Spring4.0.相关jar包:
spring-framework-4.0.2.RELEASE-dist\spring-framework-4.0.2.RELEASE\libs 目录下拷贝这些:
Hibernate4.5.1相关jar包:
在hibernate-search-4.5.1.Final-dist\hibernate-search-4.5.1.Final\dist\lib\required目录下拷贝这些必需的jar包
(BB:这里required的一些jar包跟4.5.0有些不一样,而且4.5.0有些包跟struts2.3.16.1里的重复了,重复了就用Hibernate里的。到4.5.1重复的就少了,好像就一个javassist-3.x.x.GA.jar重复了,hibernate里的版本高些,我们就用它的)
在hibernate-search-4.5.1.Final-dist\hibernate-search-4.5.1.Final\dist\lib\provided目录下拷贝这些(YY:这些是必需的,不然启动的时候就报错,大家可以试试,我就是看了启动错误信息才去加它们的):
接下来数据库驱动包,我用的是mysql5.6.14(Select @@Version使用此命令可查看数据库版本),驱动jar用的是mysql-connector-java-5.1.10.jar。
数据库连接池我用的是c3p0。
在c3p0-0.9.5-pre8.bin\c3p0-0.9.5-pre8\lib目录下拷贝:
还需要两个额外jar包(aspectjweaver.jar和aopalliance.jar):
①从官网下载的竟然是一个jar包叫aspectj-1.8.0.M1.jar。用好压解压出来,在aspectj-1.8.0.M1\lib可以看到如下jar包:
拷贝aspectjweaver.jar,以前的教程中还要加入aspectjrt.jar。我看过一篇关于spring和Hibernate集成的文章,那位印度大神没有用aspectjrt.jar。我自己试了很多遍,不用这个的确可以。而且我根据错误信息提示只加入aspectjweaver.jar这一个jar包问题就解决了。这里我们也就只用这一个jar包。我感觉jar包这东西并不是多多益善的,能精简咱尽量精简一下。
② 官网上下载的比较新的版本是aopalliance.zip,解压后就可以看到aopalliance.jar。用以前的aopalliance-1.0.jar亲测也是可以的。 但是用最新版的aopalliance-alpha1.jar就不行!
另外如果用最新版的jstl-1.2.1。可以到官网上下载。已经不是以前的jstl.jar和standard.jar了。 如果只用目前最新版的功能,不想兼容以前的版本,只需要下载这个两个jar包:taglibs-standard-spec-1.2.1.jar,taglibs-standard-impl-1.2.1.jar。
目前为止,除了struts相关jar包没有加入之外,该加的我们都加完了。为了用最新的jar包搭一个框架,我真的是殚精竭虑呀。太曲折了,说出来都是泪呀,正因为如此我才要把这些贴出来。
下面开始最麻烦的配置了。 配置的时候大家尽量从官网上下载的文档中拷贝。
这样不容易错,而且官方文档也会使用最新的和最合理的配置方式。这里就不跟大家说如果从手册上找了。
我看到网上好多直接拷贝的配置文件,感觉好乱,而且几乎都是同一个结构。
这里给出自认为较合理的配置方式,并把自己在配置过程中遇到的问题说一下。
大家知道hibernate有个hibernate.cfg.xml。网上好多人直接把c3p0和Hibernate的相关属性都配在spring里了。 我感觉这样乱不说,spring的配置文件也有些臃肿。事实上这样
并没有使spring的配置文件减小,但我个人感觉上是的,因为把许多东西都配在jdbc.properties文件里了,然后在applicationContext.xml里引用它,这样感觉上就不那么臃肿
了。而且想查看什么属性直接点开jdbc.properties就能很清楚的看到,不会跟spring的事务和bean搅在一起,这样阅读的时候心里会好受些。
在src下新建jdbc.properties文件。
内容如下:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///ahau
jdbc.username=root
jdbc.password=root
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.hbm2ddl.auto=update
hibernate.show_sql=true
hibernate.format_sql=false
hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=false
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
c3p0.acquireIncrement=5
c3p0.idleConnectionTestPeriod=60
c3p0.initialPoolSize=10
c3p0.maxIdleTime=60
c3p0.maxPoolSize=30
c3p0.maxStatements=200
c3p0.maxStatementsPerConnection=30
c3p0.minPoolSize=5
注意这里有一个巨大插曲。就在这里我已经吃过两次亏了。 这是第一次:http://blog.csdn.net/ahau10/article/details/21515453。
我这次学乖了在每个属性前面都加上前缀了,几乎所有的官方文档上也都是这么写的。 我以为这回这样写总不会错了吧。
请看下面的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-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="cn.ahau"/>
<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}"/>
<!-- <property name="acquireIncrement" value="${c3p0.acquireIncrement}"/> -->
<property name="idleConnectionTestPeriod" value="${c3p0.idleConnectionTestPeriod}"/>
<property name="initialPoolSize" value="${c3p0.initialPoolSize}"/>
<property name="maxIdleTime" value="${c3p0.maxIdleTime}"/>
<property name="maxPoolSize" value="${c3p0.maxPoolSize}"/>
<property name="maxStatements" value="${c3p0.maxStatements}"/>
<property name="maxStatementsPerConnection" value="${c3p0.maxStatementsPerConnection}"/>
<property name="minPoolSize" value="${c3p0.minPoolSize}"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>cn/ahau/domain/User.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="dialect">${hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="show_sql">${hibernate.show_sql}</prop>
<prop key="format_sql">${hibernate.format_sql}</prop>
<prop key="cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</prop>
<prop key="cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
<prop key="cache.provider_class">${hibernate.cache.provider_class}</prop>
<prop key="hibernate.current_session_context_class">${hibernate.current_session_context_class}</prop>
</props>
</property>
</bean>
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 第一种方法配置事务 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="userDao" class="cn.ahau.dao.impl.UserDaoImpl"/>
</beans>
我用红色标记的地方就是我第二次栽的地方。 开始的时候我写成这样:<prop key="hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>,我以为这个key随便写写没什么嘛,毕竟后面都写对了,启动的时候也不报错。可是在我开始保存对象的时候报错了,总是说表不存在!我想当然的以为Hibernate会自动创建表呢。谁知道这里的key不加前缀它就识别不了啊。。。
下面依次在src下建 包、表、对象映射文件。
User.java
package cn.ahau.domain;
public class User {
private int id;
private String name;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User() {
super();
}
}
UserDao.java
import cn.ahau.domain.User;
public interface UserDao {
void add(User user);
User query(String fieldName);
}
UserDaoImpl.java
package cn.ahau.dao.impl;
import javax.annotation.Resource;
import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import cn.ahau.dao.UserDao;
import cn.ahau.domain.User;
@Transactional
public class UserDaoImpl implements UserDao{
@Resource
private SessionFactory sessionFactory;
public void add(User user) {
sessionFactory.getCurrentSession().save(user);
}
@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
@SuppressWarnings("unchecked")
public User query(String fieldName) {
Criteria c = sessionFactory.openSession().createCriteria(User.class);
c.add(Restrictions.eq("name", fieldName));
User u = (User) c.uniqueResult();
return u;
}
}
注意这里又有巨大插曲了。 先看query方法,只是查询因此不希望开启事务,这里为什么是openSession。而不是跟save方法一样采用sessionFactory.getCurrentSession()这种方式。 解决这个问题实在是太曲折了。如果采用sessionFactory.getCurrentSession()这种方式,则报:createQuery is not valid without active transaction。网上好多都说改这个配置(这个在jdbc.properties里)hibernate.current_session_context_class,改成thread和其他的都不行。改成thread则引报其他错误。最后终于找到一篇文章,解决办法就是用openSession。 原文地址如下:
http://blog.csdn.net/wzk527/article/details/8543480
在看看save方法。以前的教程用jta的时候是用persist()方法的。现在使用persist方法时,第一次表单提交时保存能成功,浏览器点击回退时再次保存就会报
detached entity passed to persist。改成save方法时问题解决。 关于session这一块儿我还不大清楚,也许还有其他的解决办法。
User.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.ahau.domain">
<class name="User" table="user">
<id name="id">
<generator class="native"/>
</id>
<property name="name" column="name" unique="true"/>
<property name="password" column="password"/>
</class>
</hibernate-mapping>
这里也有个小插曲。如果保存不成功,报类似于如下错误:
Could not get constructor for org.hibernate.persister.entity.SingleTableEntityPersister
仔细检查实体类的字段例如password name 等名称可能是数据库保留字,所以最好取个别名。
UserTest.java
package cn.ahau.test;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.ahau.dao.UserDao;
import cn.ahau.domain.User;
public class UserTest {
private static UserDao userDao;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
try {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
userDao = (UserDao)applicationContext.getBean("userDao");
} catch (RuntimeException e) {
e.printStackTrace();
}
}
@Test
public void testAddUser() {
User user = new User();
user.setName("hh");
user.setPassword("aa");
userDao.add(user);
}
}
运行后出现绿条,检查数据库user表已经创立。SH已经搭好了,现在只剩下最好一步了。
在WEB-INF/下,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>ssh2</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 对Spring容器进行实例化 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置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>
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param>
</filter>
</web-app>
在src下,新建cn.ahau.action包,UserAction 类。
UserAction.java
package cn.ahau.action;
public class UserAction {
public String test(){
return "home";
}
}
在src下新建struts.xml
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>
<!-- 指定Web应用的默认编码集,相当于调用HttpServletRequest的setCharacterEncoding方法 -->
<constant name="struts.i18n.encoding" value="UTF-8"/>
<!-- 该属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts2处理。
如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。 -->
<constant name="struts.action.extension" value="do,action"/>
<!-- 设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭 -->
<constant name="struts.serve.static.browserCache" value="false"/>
<!-- 当struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生产环境下使用),开发阶段最好打开 -->
<constant name="struts.configuration.xml.reload" value="true"/>
<!-- 开发模式下使用,这样可以打印出更详细的错误信息 -->
<constant name="struts.devMode" value="true" />
<!-- 默认的视图主题 -->
<constant name="struts.ui.theme" value="simple" />
<!-- action对象由spring负责创建 -->
<constant name="struts.objectFactory" value="spring" />
<package name="user" namespace="/user" extends="struts-default">
<action name="action_*" class="userList" method="{1}">
<result name="home">/index.jsp</result>
</action>
</package>
</struts>
小插曲: <constant name="struts.objectFactory" value="spring" />这一句表明把action交由spring管理。因此要确保1)struts2-spring-plugin-2.3.16.1.jar已经加入到build path中。 2) applicationContext.xml中配置了相关的bean。 这里要在此xml下追加<bean id="userList" class="cn.ahau.action.UserAction"/>
然后在WebCotent目录下新建一个index.jsp。
将项目加入到服务器中,启动服务器后,出现片红色信息,最后几句类似于如下:
四月 29, 2014 11:59:30 下午 org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-apr-8080"]
四月 29, 2014 11:59:30 下午 org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-apr-8009"]
四月 29, 2014 11:59:30 下午 org.apache.catalina.startup.Catalina start
INFO: Server startup in 10803 ms
恭喜你启动成功了。 在浏览器地址栏输入:http://localhost:8080/cjbssh2/user/action_test.do
回车后你就能看到index.jsp里的内容了。 这里为了省事并没有写service层。 说的有些乱,又有些粗糙。主要是跟大家分享一下心得。本文最大的价值恐怕也就是这个几个jar包了。我将这个小Demo传上来了,虽然没什么价值,但是xml配置都是我一点一点垒起来的,很多都是是从官方手册上拷贝下来的。 本人也是第一次搭框架,有什么错误的地方还请指出,以免误导他人,写写。
demo地址:http://download.csdn.net/detail/ahau10/7273531
New-->other-->搜索框输入Junit,选择junit test case ,输入名称UserTest,
注意勾选上setUpBeforeClass