我这里使用的是spring4.2.2+struts2的 2.3.24+hibernate 5.0.7 进行的SSH整合
注意: struts2和hibernate的核心jar包中都有一个jar包 版本不一样 叫javassist 这个会导致报错 需要删掉一个
导入jar包什么的就不说了 直接说说配置 首先spring配置文件
<!-- 配置扫描包 我spring能使用注解 尽量都是使用注解 -->
<context:component-scan base-package="包名"></context:component-scan>
<!-- 配置数据源 我这里配的是C3P0连接池 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="连接驱动类路径" />
<property name="jdbcUrl" value="连接字符串"/>
<property name="user" value="用户名"/>
<property name="password" value="密码"/>
</bean>
<!-- 这里将原本hibernate的配置信息 全部整合到spring里面来了 -->
<!-- 创建hibernate的session工厂对象 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- 注入连接池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 设置hibernate配置信息 -->
<property name="hibernateProperties">
<props>
<!-- 设置hibernate连接数据库方言 我这里使用的是mysql -->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<!-- 设置hibernate打印执行的sql语句 -->
<prop key="hibernate.show_sql">true</prop>
<!-- 设置hibernate将打印的sql语句格式化 -->
<prop key="hibernate.format_sql">true</prop>
<!-- 设置hibernate设置自动建表 -->
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<!-- 引入映射文件 -->
<property name="mappingResources">
<list>
<value>src目录下的映射文件的路径 如果多个映射文件就添加多个value标签即可 </value>
</list>
</property>
</bean>
<!-- 配置事务管理器 -->
<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 配置 事务管理 开始(事务感觉使用xml配置之后比使用注解方便 不用一个一个去加那个注解)-->
<!-- 配置通知 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="query*" read-only="true"/> <!-- query开头的任意方法 为只读方法 提高性能 -->
<tx:method name="*" rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<aop:pointcut expression="execution(* com.包名.包名..*(..))" id="pointcut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>
<!-- 配置 事务管理 结束-->
由于所有dao实现类都直接或间接继承了HibernateDaoSupport类 使用这个类的HibernateTemplate对象操作数据库 要注入sessionFactory实例才能操作数据库
但是这个类不是自己编写的 只能通过xml方式 交给spring管理 才能注入sessionFactory实例
<bean name="userDao" class="完整类名">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
我已经将hibernate的配置已经整合到了spring配置文件中 然后struts2的action也是要交给spring管理了
只需要在action类上加这两个注解
@Controller("action简短类名首字母小写 比如UserAction 就是 userAction 其实也可以随便取 在struts2的配置中要用到这个名字")
@Scope("prototype")
这个是设置bean的作用域 设置为这个值 代表每一次spring都会创建一个新的实例 默认是只有一个实例 因为action是多例的 每次请求都是一个新的实例 不写会报错 有问题
然后在struts2配置文件中 配置action时 class属性的值就是action类上@Controller()注解里面的值 剩下struts2的所有配置和正常使用没区别
--------------------------------------------------------------------------------
框架的配置文件说完了 在说一下web.xml的配置
<!-- 配置Spring的核心监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 容器初始化加载spring配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring配置文件路径</param-value>
</context-param>
<!-- 解决hibernate延迟加载 由于session已关闭 无法查询关联对象值
因为hibernate默认查询一个对象,有关联对象时是生成代理对象 而不是立即发送语句查询 这是为了提高性能 只有实际使用这个对象时 才会立即去查
但是hibernate默认在dao层操作完数据库就关闭了session连接 那么在其他地方 使用到关联对象 想去查询时 session已关闭 就会报错
-->
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
<!-- 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>
web.xml配置基本上就这些
----------------------------------------------------------
由于hibernate是自动化很高的orm框架 可以定义一个通用的dao接口 有通用的增删改查方法 其他的dao接口只需要继承这个接口 就有了这些方法
然后其他dao接口的实现类 在继承这个通用dao接口的实现类 就实现了如果只是基本的增删改查 不需要单独写方法
接下来上代码
1 /** 2 * 通用基础dao接口 3 * 可以实现增删改和根据id查询 和分页查询 4 * 5 * */ 6 public interface BaseDao<T> { 7 8 //通用保存方法 9 public Integer save(T t); 10 11 //通用修改方法 12 public void update(T t); 13 14 //通用删除方法 15 public void delete(T t); 16 17 //通用根据主键查询方法 18 public T queryByID(Serializable id); 19 20 //通用 查询全部方法 21 public List<T> queryAll(); 22 23 24 //通用 查询总记录数 配合分页查询使用 25 public Integer queryRowCount(DetachedCriteria dc); 26 27 //通用分页查询方法 参1:离线条件查询对象 参2:自定义的分页帮助类 28 public void queryPage(DetachedCriteria dc,Pagination p); 29 30 31 32 33 }
因为hibernate增删改方法都是传入具体要操作的实体类的对象 所以只能使用泛型
接下来就是dao接口的实现类
public class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T> { //定义这个属性 从无参构造方法中 获得实际要进行操作实体类的class对象 private Class clazz; /** * 在这个构造方法中 获得继承这个类的子类,上写的泛型的实际类型 * 例如 UserDaoImpl extends BaseDaoImpl<User> * 就是要获得这个泛型的实际类型 这个User * */ public BaseDaoImpl() { //子类实例化时,会调用父类构造方法,通过this指向的就是子类的对象,得到了子类的class对象 Class child=this.getClass(); //获得父类的泛型参数对象 ParameterizedType type =(ParameterizedType) child.getGenericSuperclass(); //获得泛型对象的实际类型 由于泛型可以有多个参数 例如 Map<String,Object> //所以返回得是数组 取出第一个 强转成Class对象 赋值给属性 就得到了实际操作的实体类的class this.clazz= (Class)type.getActualTypeArguments()[0]; } public Integer save(T t) { return (Integer)this.getHibernateTemplate().save(t); } public void update(T t) { this.getHibernateTemplate().update(t); } public void delete(T t) { this.getHibernateTemplate().delete(t); } public T queryByID(Serializable id) { return (T)this.getHibernateTemplate().get(clazz, id); } public List<T> queryAll() { return (List<T>)this.getHibernateTemplate().find("from "+clazz.getSimpleName()); } public Integer queryRowCount(DetachedCriteria dc) { dc.setProjection(Projections.rowCount());//设置离线条件查询对象执行count聚合函数 List list = this.getHibernateTemplate().findByCriteria(dc);//执行查询 return list.size()>0?((Long)list.get(0)).intValue():0; } public void queryPage(DetachedCriteria dc, Pagination p) { dc.setProjection(null);//离线条件查询对象,刚刚执行聚合函数操作,设置为null代表 不使用聚合函数 //执行查询 参数1:离线条件查询对象,参数2:查询记录的起始索引,参3:查询几条记录 List list = this.getHibernateTemplate().findByCriteria(dc, (p.getCurrentPage()-1)*p.getPageSize(), p.getPageSize()); p.setList(list); } }
这个实现类核心就在无参构造方法 子类实现这个类以后 实例化 调用父类的构造方法 就可以得到子类泛型上的具体类型 然后赋值给父类中的class对象
得到了class对象 就可以实现查询了
演示使用
public interface UserDao extends BaseDao<User> { }
UserDao接口继承了通用dao接口 并且设置了实际的类型
这时候Userdao接口就有了通用的增删改查方法
public class UserDaoImpl extends BaseDaoImpl<User> implements UserDao { }
UserDao的实现类 继承了通用dao接口的实现类 并且实现了UserDao接口
这个时候如果只要使用基本的增删改查方法 在UserDaoImpl中不需要写额外的方法
这一点还是很方便的 mybatis就做不到
我把我自己用的分页帮助类也发上来吧
public class Pagination { private List list; private int currentPage=1;//当前页码 private int pageSize=3;//每页个数 private int rowCount;//总记录数 public List getList() { return list; } public void setList(List list) { this.list = list; } public int getCurrentPage() { return currentPage; } public void setCurrentPage(int currentPage) { this.currentPage = currentPage; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public int getRowCount() { return rowCount; } public void setRowCount(int rowCount) { this.rowCount = rowCount; } public int getStartPage(){ //第一页 return 1; } public int getEndPage(){ //最后一页 return this.getPageCount(); } public int getPageCount(){ //总页数 return this.rowCount%this.pageSize==0?this.rowCount/this.pageSize:this.rowCount/this.pageSize+1; } public int getprevPage(){//上一页 return this.currentPage>1?this.currentPage-1:1; } public int getnextPage(){//下一页 return this.currentPage==getEndPage()?getEndPage():this.currentPage+1; } }
SSH整合 基本上就这么多东西